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