• 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 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 
30 // list of extensions supported by this EGL implementation only if supported
31 // on the host implementation.
32 //  NOTE that each extension name should be suffixed with space
33 static const char systemDynamicEGLExtensions[] =
34             "EGL_KHR_image_base "
35             "EGL_KHR_gl_texture_2d_image ";
36 
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 }
73 
~eglDisplay()74 eglDisplay::~eglDisplay()
75 {
76     pthread_mutex_destroy(&m_lock);
77 }
78 
initialize(EGLClient_eglInterface * eglIface)79 bool eglDisplay::initialize(EGLClient_eglInterface *eglIface)
80 {
81     pthread_mutex_lock(&m_lock);
82     if (!m_initialized) {
83 
84         //
85         // load GLES client API
86         //
87 #if __LP64__
88         m_gles_iface = loadGLESClientAPI("/system/lib64/egl/libGLESv1_CM_emulation.so",
89                                          eglIface,
90                                          &s_gles_lib);
91 #else
92         m_gles_iface = loadGLESClientAPI("/system/lib/egl/libGLESv1_CM_emulation.so",
93                                          eglIface,
94                                          &s_gles_lib);
95 #endif
96         if (!m_gles_iface) {
97             pthread_mutex_unlock(&m_lock);
98             ALOGE("Failed to load gles1 iface");
99             return false;
100         }
101 
102 #ifdef WITH_GLES2
103 #if __LP64__
104         m_gles2_iface = loadGLESClientAPI("/system/lib64/egl/libGLESv2_emulation.so",
105                                           eglIface,
106                                           &s_gles2_lib);
107 #else
108         m_gles2_iface = loadGLESClientAPI("/system/lib/egl/libGLESv2_emulation.so",
109                                           eglIface,
110                                           &s_gles2_lib);
111 #endif
112         // Note that if loading gles2 failed, we can still run with no
113         // GLES2 support, having GLES2 is not mandatory.
114 #endif
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         m_configs = new EGLint[nInts-m_numConfigAttribs];
172         if (!m_configs) {
173             pthread_mutex_unlock(&m_lock);
174             return false;
175         }
176 
177         //EGLint n = rcEnc->rcGetConfigs(rcEnc, nInts*sizeof(EGLint), m_configs);
178         EGLint n = rcEnc->rcGetConfigs(rcEnc, nInts*sizeof(EGLint), (GLuint*)tmp_buf);
179         if (n != m_numConfigs) {
180             pthread_mutex_unlock(&m_lock);
181             return false;
182         }
183 
184         //Fill the attributes vector.
185         //The first m_numConfigAttribs values of tmp_buf are the actual attributes enums.
186         for (int i=0; i<m_numConfigAttribs; i++) {
187             m_attribs.add(tmp_buf[i], i);
188         }
189 
190         //Copy the actual configs data to m_configs
191         memcpy(m_configs, tmp_buf + m_numConfigAttribs, m_numConfigs*m_numConfigAttribs*sizeof(EGLint));
192 
193         m_initialized = true;
194     }
195     pthread_mutex_unlock(&m_lock);
196 
197     processConfigs();
198 
199     return true;
200 }
201 
processConfigs()202 void eglDisplay::processConfigs()
203 {
204     for (intptr_t i=0; i<m_numConfigs; i++) {
205         EGLConfig config = (EGLConfig)i;
206         //Setup the EGL_NATIVE_VISUAL_ID attribute
207         PixelFormat 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         m_initialized = false;
219         delete [] m_configs;
220         m_configs = NULL;
221 
222         if (m_versionString) {
223             free(m_versionString);
224             m_versionString = NULL;
225         }
226         if (m_vendorString) {
227             free(m_vendorString);
228             m_vendorString = NULL;
229         }
230         if (m_extensionString) {
231             free(m_extensionString);
232             m_extensionString = NULL;
233         }
234     }
235     pthread_mutex_unlock(&m_lock);
236 }
237 
loadGLESClientAPI(const char * libName,EGLClient_eglInterface * eglIface,void ** libHandle)238 EGLClient_glesInterface *eglDisplay::loadGLESClientAPI(const char *libName,
239                                                        EGLClient_eglInterface *eglIface,
240                                                        void **libHandle)
241 {
242     void *lib = dlopen(libName, RTLD_NOW);
243     if (!lib) {
244         ALOGE("Failed to dlopen %s", libName);
245         return NULL;
246     }
247 
248     init_emul_gles_t init_gles_func = (init_emul_gles_t)dlsym(lib,"init_emul_gles");
249     if (!init_gles_func) {
250         ALOGE("Failed to find init_emul_gles");
251         dlclose((void*)lib);
252         return NULL;
253     }
254 
255     *libHandle = lib;
256     return (*init_gles_func)(eglIface);
257 }
258 
queryHostEGLString(EGLint name)259 static char *queryHostEGLString(EGLint name)
260 {
261     HostConnection *hcon = HostConnection::get();
262     if (hcon) {
263         renderControl_encoder_context_t *rcEnc = hcon->rcEncoder();
264         if (rcEnc) {
265             int n = rcEnc->rcQueryEGLString(rcEnc, name, NULL, 0);
266             if (n < 0) {
267                 // allocate space for the string with additional
268                 // space charachter to be suffixed at the end.
269                 char *str = (char *)malloc(-n+2);
270                 n = rcEnc->rcQueryEGLString(rcEnc, name, str, -n);
271                 if (n > 0) {
272                     // add extra space at end of string which will be
273                     // needed later when filtering the extension list.
274                     strcat(str, " ");
275                     return str;
276                 }
277 
278                 free(str);
279             }
280         }
281     }
282 
283     return NULL;
284 }
285 
findExtInList(const char * token,int tokenlen,const char * list)286 static bool findExtInList(const char* token, int tokenlen, const char* list)
287 {
288     const char* p = list;
289     while (*p != '\0') {
290         const char* q = strchr(p, ' ');
291         if (q == NULL) {
292             /* should not happen, list must be space-terminated */
293             break;
294         }
295         if (tokenlen == (q - p) && !memcmp(token, p, tokenlen)) {
296             return true;  /* found it */
297         }
298         p = q+1;
299     }
300     return false;  /* not found */
301 }
302 
buildExtensionString()303 static char *buildExtensionString()
304 {
305     //Query host extension string
306     char *hostExt = queryHostEGLString(EGL_EXTENSIONS);
307     if (!hostExt || (hostExt[1] == '\0')) {
308         // no extensions on host - only static extension list supported
309         return strdup(systemStaticEGLExtensions);
310     }
311 
312     //
313     // Filter host extension list to include only extensions
314     // we can support (in the systemDynamicEGLExtensions list)
315     //
316     char *ext = (char *)hostExt;
317     char *c = ext;
318     char *insert = ext;
319     while(*c != '\0') {
320         if (*c == ' ') {
321             int len = c - ext;
322             if (findExtInList(ext, len, systemDynamicEGLExtensions)) {
323                 if (ext != insert) {
324                     memcpy(insert, ext, len+1); // including space
325                 }
326                 insert += (len + 1);
327             }
328             ext = c + 1;
329         }
330         c++;
331     }
332     *insert = '\0';
333 
334     int n = strlen(hostExt);
335     if (n > 0) {
336         char *str;
337         asprintf(&str,"%s%s", systemStaticEGLExtensions, hostExt);
338         free((char*)hostExt);
339         return str;
340     }
341     else {
342         free((char*)hostExt);
343         return strdup(systemStaticEGLExtensions);
344     }
345 }
346 
queryString(EGLint name)347 const char *eglDisplay::queryString(EGLint name)
348 {
349     if (name == EGL_CLIENT_APIS) {
350         return "OpenGL_ES";
351     }
352     else if (name == EGL_VERSION) {
353         pthread_mutex_lock(&m_lock);
354         if (m_versionString) {
355             pthread_mutex_unlock(&m_lock);
356             return m_versionString;
357         }
358 
359         // build version string
360         asprintf(&m_versionString, "%d.%d", m_major, m_minor);
361         pthread_mutex_unlock(&m_lock);
362 
363         return m_versionString;
364     }
365     else if (name == EGL_VENDOR) {
366         pthread_mutex_lock(&m_lock);
367         if (m_vendorString) {
368             pthread_mutex_unlock(&m_lock);
369             return m_vendorString;
370         }
371 
372         // build vendor string
373         const char *hostVendor = queryHostEGLString(EGL_VENDOR);
374 
375         if (hostVendor) {
376             asprintf(&m_vendorString, "%s Host: %s",
377                                      systemEGLVendor, hostVendor);
378             free((char*)hostVendor);
379         }
380         else {
381             m_vendorString = (char *)systemEGLVendor;
382         }
383         pthread_mutex_unlock(&m_lock);
384 
385         return m_vendorString;
386     }
387     else if (name == EGL_EXTENSIONS) {
388         pthread_mutex_lock(&m_lock);
389         if (m_extensionString) {
390             pthread_mutex_unlock(&m_lock);
391             return m_extensionString;
392         }
393 
394         // build extension string
395         m_extensionString = buildExtensionString();
396         pthread_mutex_unlock(&m_lock);
397 
398         return m_extensionString;
399     }
400     else {
401         ALOGE("[%s] Unknown name %d\n", __FUNCTION__, name);
402         return NULL;
403     }
404 }
405 
406 /* To get the value of attribute <a> of config <c> use the following formula:
407  * value = *(m_configs + (int)c*m_numConfigAttribs + a);
408  */
getAttribValue(EGLConfig config,EGLint attribIdx,EGLint * value)409 EGLBoolean eglDisplay::getAttribValue(EGLConfig config, EGLint attribIdx, EGLint * value)
410 {
411     if (attribIdx == ATTRIBUTE_NONE)
412     {
413         ALOGE("[%s] Bad attribute idx\n", __FUNCTION__);
414         return EGL_FALSE;
415     }
416     *value = *(m_configs + (intptr_t)config*m_numConfigAttribs + attribIdx);
417     return EGL_TRUE;
418 }
419 
getConfigAttrib(EGLConfig config,EGLint attrib,EGLint * value)420 EGLBoolean eglDisplay::getConfigAttrib(EGLConfig config, EGLint attrib, EGLint * value)
421 {
422     //Though it seems that valueFor() is thread-safe, we don't take chanses
423     pthread_mutex_lock(&m_lock);
424     EGLBoolean ret = getAttribValue(config, m_attribs.valueFor(attrib), value);
425     pthread_mutex_unlock(&m_lock);
426     return ret;
427 }
428 
dumpConfig(EGLConfig config)429 void eglDisplay::dumpConfig(EGLConfig config)
430 {
431     EGLint value = 0;
432     DBG("^^^^^^^^^^ dumpConfig %d ^^^^^^^^^^^^^^^^^^", (int)config);
433     for (int i=0; i<m_numConfigAttribs; i++) {
434         getAttribValue(config, i, &value);
435         DBG("{%d}[%d] %d\n", (int)config, i, value);
436     }
437 }
438 
439 /* To set the value of attribute <a> of config <c> use the following formula:
440  * *(m_configs + (int)c*m_numConfigAttribs + a) = value;
441  */
setAttribValue(EGLConfig config,EGLint attribIdx,EGLint value)442 EGLBoolean eglDisplay::setAttribValue(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     *(m_configs + (intptr_t)config*m_numConfigAttribs + attribIdx) = value;
450     return EGL_TRUE;
451 }
452 
setConfigAttrib(EGLConfig config,EGLint attrib,EGLint value)453 EGLBoolean eglDisplay::setConfigAttrib(EGLConfig config, EGLint attrib, EGLint value)
454 {
455     //Though it seems that valueFor() is thread-safe, we don't take chanses
456     pthread_mutex_lock(&m_lock);
457     EGLBoolean ret = setAttribValue(config, m_attribs.valueFor(attrib), value);
458     pthread_mutex_unlock(&m_lock);
459     return ret;
460 }
461 
462 
getConfigNativePixelFormat(EGLConfig config,PixelFormat * format)463 EGLBoolean eglDisplay::getConfigNativePixelFormat(EGLConfig config, PixelFormat * format)
464 {
465     EGLint redSize, blueSize, greenSize, alphaSize;
466 
467     if ( !(getAttribValue(config, m_attribs.valueFor(EGL_RED_SIZE), &redSize) &&
468         getAttribValue(config, m_attribs.valueFor(EGL_BLUE_SIZE), &blueSize) &&
469         getAttribValue(config, m_attribs.valueFor(EGL_GREEN_SIZE), &greenSize) &&
470         getAttribValue(config, m_attribs.valueFor(EGL_ALPHA_SIZE), &alphaSize)) )
471     {
472         ALOGE("Couldn't find value for one of the pixel format attributes");
473         return EGL_FALSE;
474     }
475 
476     //calculate the GL internal format
477     if ((redSize==8)&&(greenSize==8)&&(blueSize==8)&&(alphaSize==8)) *format = PIXEL_FORMAT_RGBA_8888; //XXX: BGR?
478     else if ((redSize==8)&&(greenSize==8)&&(blueSize==8)&&(alphaSize==0)) *format = PIXEL_FORMAT_RGBX_8888; //XXX or PIXEL_FORMAT_RGB_888
479     else if ((redSize==5)&&(greenSize==6)&&(blueSize==5)&&(alphaSize==0)) *format = PIXEL_FORMAT_RGB_565;
480     else if ((redSize==5)&&(greenSize==5)&&(blueSize==5)&&(alphaSize==1)) *format = PIXEL_FORMAT_RGBA_5551;
481     else if ((redSize==4)&&(greenSize==4)&&(blueSize==4)&&(alphaSize==4)) *format = PIXEL_FORMAT_RGBA_4444;
482     else {
483         return EGL_FALSE;
484     }
485     return EGL_TRUE;
486 }
getConfigGLPixelFormat(EGLConfig config,GLenum * format)487 EGLBoolean eglDisplay::getConfigGLPixelFormat(EGLConfig config, GLenum * format)
488 {
489     EGLint redSize, blueSize, greenSize, alphaSize;
490 
491     if ( !(getAttribValue(config, m_attribs.valueFor(EGL_RED_SIZE), &redSize) &&
492         getAttribValue(config, m_attribs.valueFor(EGL_BLUE_SIZE), &blueSize) &&
493         getAttribValue(config, m_attribs.valueFor(EGL_GREEN_SIZE), &greenSize) &&
494         getAttribValue(config, m_attribs.valueFor(EGL_ALPHA_SIZE), &alphaSize)) )
495     {
496         ALOGE("Couldn't find value for one of the pixel format attributes");
497         return EGL_FALSE;
498     }
499 
500     //calculate the GL internal format
501     if ((redSize==8)&&(blueSize==8)&&(blueSize==8)&&(alphaSize==8)) *format = GL_RGBA;
502     else if ((redSize==8)&&(greenSize==8)&&(blueSize==8)&&(alphaSize==0)) *format = GL_RGB;
503     else if ((redSize==5)&&(greenSize==6)&&(blueSize==5)&&(alphaSize==0)) *format = GL_RGB565_OES;
504     else if ((redSize==5)&&(greenSize==5)&&(blueSize==5)&&(alphaSize==1)) *format = GL_RGB5_A1_OES;
505     else if ((redSize==4)&&(greenSize==4)&&(blueSize==4)&&(alphaSize==4)) *format = GL_RGBA4_OES;
506     else return EGL_FALSE;
507 
508     return EGL_TRUE;
509 }
510