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