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 
     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
     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 
     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 
     74 eglDisplay::~eglDisplay()
     75 {
     76     pthread_mutex_destroy(&m_lock);
     77 }
     78 
     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 
    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 
    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 
    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 
    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 
    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 
    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 
    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  */
    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 
    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 
    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  */
    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 
    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 
    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 }
    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