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