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