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 #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
     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     pthread_mutex_init(&m_ctxLock, NULL);
     72     pthread_mutex_init(&m_surfaceLock, NULL);
     73 }
     74 
     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 
     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 
    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 
    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 
    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 
    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 
    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 
    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 
    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  */
    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 
    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 
    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  */
    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 
    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 
    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 }
    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 
    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 
    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 
    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 
    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