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