Home | History | Annotate | Download | only in egl
      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
     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 
     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 
     68 eglDisplay::~eglDisplay()
     69 {
     70     pthread_mutex_destroy(&m_lock);
     71 }
     72 
     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 
    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 
    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 
    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 
    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 
    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 
    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 
    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  */
    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 
    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 
    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  */
    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 
    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 
    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 }
    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