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