Home | History | Annotate | Download | only in EGL
      1 /*
      2  ** Copyright 2007, 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 
     17 #include <ctype.h>
     18 #include <stdlib.h>
     19 #include <stdio.h>
     20 #include <string.h>
     21 #include <errno.h>
     22 #include <dlfcn.h>
     23 #include <limits.h>
     24 #include <dirent.h>
     25 
     26 #include <cutils/log.h>
     27 #include <cutils/properties.h>
     28 
     29 #include <EGL/egl.h>
     30 
     31 #include "../glestrace.h"
     32 
     33 #include "egldefs.h"
     34 #include "Loader.h"
     35 
     36 // ----------------------------------------------------------------------------
     37 namespace android {
     38 // ----------------------------------------------------------------------------
     39 
     40 
     41 /*
     42  * EGL userspace drivers must be provided either:
     43  * - as a single library:
     44  *      /vendor/lib/egl/libGLES.so
     45  *
     46  * - as separate libraries:
     47  *      /vendor/lib/egl/libEGL.so
     48  *      /vendor/lib/egl/libGLESv1_CM.so
     49  *      /vendor/lib/egl/libGLESv2.so
     50  *
     51  * The software renderer for the emulator must be provided as a single
     52  * library at:
     53  *
     54  *      /system/lib/egl/libGLES_android.so
     55  *
     56  *
     57  * For backward compatibility and to facilitate the transition to
     58  * this new naming scheme, the loader will additionally look for:
     59  *
     60  *      /{vendor|system}/lib/egl/lib{GLES | [EGL|GLESv1_CM|GLESv2]}_*.so
     61  *
     62  */
     63 
     64 ANDROID_SINGLETON_STATIC_INSTANCE( Loader )
     65 
     66 /* This function is called to check whether we run inside the emulator,
     67  * and if this is the case whether GLES GPU emulation is supported.
     68  *
     69  * Returned values are:
     70  *  -1   -> not running inside the emulator
     71  *   0   -> running inside the emulator, but GPU emulation not supported
     72  *   1   -> running inside the emulator, GPU emulation is supported
     73  *          through the "emulation" config.
     74  */
     75 static int
     76 checkGlesEmulationStatus(void)
     77 {
     78     /* We're going to check for the following kernel parameters:
     79      *
     80      *    qemu=1                      -> tells us that we run inside the emulator
     81      *    android.qemu.gles=<number>  -> tells us the GLES GPU emulation status
     82      *
     83      * Note that we will return <number> if we find it. This let us support
     84      * more additionnal emulation modes in the future.
     85      */
     86     char  prop[PROPERTY_VALUE_MAX];
     87     int   result = -1;
     88 
     89     /* First, check for qemu=1 */
     90     property_get("ro.kernel.qemu",prop,"0");
     91     if (atoi(prop) != 1)
     92         return -1;
     93 
     94     /* We are in the emulator, get GPU status value */
     95     property_get("ro.kernel.qemu.gles",prop,"0");
     96     return atoi(prop);
     97 }
     98 
     99 // ----------------------------------------------------------------------------
    100 
    101 static char const * getProcessCmdline() {
    102     long pid = getpid();
    103     char procPath[128];
    104     snprintf(procPath, 128, "/proc/%ld/cmdline", pid);
    105     FILE * file = fopen(procPath, "r");
    106     if (file) {
    107         static char cmdline[256];
    108         char *str = fgets(cmdline, sizeof(cmdline) - 1, file);
    109         fclose(file);
    110         if (str) {
    111             return cmdline;
    112         }
    113     }
    114     return NULL;
    115 }
    116 
    117 // ----------------------------------------------------------------------------
    118 
    119 Loader::driver_t::driver_t(void* gles)
    120 {
    121     dso[0] = gles;
    122     for (size_t i=1 ; i<NELEM(dso) ; i++)
    123         dso[i] = 0;
    124 }
    125 
    126 Loader::driver_t::~driver_t()
    127 {
    128     for (size_t i=0 ; i<NELEM(dso) ; i++) {
    129         if (dso[i]) {
    130             dlclose(dso[i]);
    131             dso[i] = 0;
    132         }
    133     }
    134 }
    135 
    136 status_t Loader::driver_t::set(void* hnd, int32_t api)
    137 {
    138     switch (api) {
    139         case EGL:
    140             dso[0] = hnd;
    141             break;
    142         case GLESv1_CM:
    143             dso[1] = hnd;
    144             break;
    145         case GLESv2:
    146             dso[2] = hnd;
    147             break;
    148         default:
    149             return BAD_INDEX;
    150     }
    151     return NO_ERROR;
    152 }
    153 
    154 // ----------------------------------------------------------------------------
    155 
    156 Loader::Loader()
    157     : getProcAddress(NULL) {
    158 }
    159 
    160 Loader::~Loader() {
    161     GLTrace_stop();
    162 }
    163 
    164 static void* load_wrapper(const char* path) {
    165     void* so = dlopen(path, RTLD_NOW | RTLD_LOCAL);
    166     ALOGE_IF(!so, "dlopen(\"%s\") failed: %s", path, dlerror());
    167     return so;
    168 }
    169 
    170 void* Loader::open(egl_connection_t* cnx)
    171 {
    172     void* dso;
    173     driver_t* hnd = 0;
    174 
    175     dso = load_driver("GLES", cnx, EGL | GLESv1_CM | GLESv2);
    176     if (dso) {
    177         hnd = new driver_t(dso);
    178     } else {
    179         // Always load EGL first
    180         dso = load_driver("EGL", cnx, EGL);
    181         if (dso) {
    182             hnd = new driver_t(dso);
    183             hnd->set( load_driver("GLESv1_CM", cnx, GLESv1_CM), GLESv1_CM );
    184             hnd->set( load_driver("GLESv2",    cnx, GLESv2),    GLESv2 );
    185         }
    186     }
    187 
    188     LOG_ALWAYS_FATAL_IF(!hnd, "couldn't find an OpenGL ES implementation");
    189 
    190     cnx->libGles2 = load_wrapper("/system/lib/libGLESv2.so");
    191     cnx->libGles1 = load_wrapper("/system/lib/libGLESv1_CM.so");
    192     LOG_ALWAYS_FATAL_IF(!cnx->libGles2 || !cnx->libGles1,
    193             "couldn't load system OpenGL ES wrapper libraries");
    194 
    195     return (void*)hnd;
    196 }
    197 
    198 status_t Loader::close(void* driver)
    199 {
    200     driver_t* hnd = (driver_t*)driver;
    201     delete hnd;
    202     return NO_ERROR;
    203 }
    204 
    205 void Loader::init_api(void* dso,
    206         char const * const * api,
    207         __eglMustCastToProperFunctionPointerType* curr,
    208         getProcAddressType getProcAddress)
    209 {
    210     const ssize_t SIZE = 256;
    211     char scrap[SIZE];
    212     while (*api) {
    213         char const * name = *api;
    214         __eglMustCastToProperFunctionPointerType f =
    215             (__eglMustCastToProperFunctionPointerType)dlsym(dso, name);
    216         if (f == NULL) {
    217             // couldn't find the entry-point, use eglGetProcAddress()
    218             f = getProcAddress(name);
    219         }
    220         if (f == NULL) {
    221             // Try without the OES postfix
    222             ssize_t index = ssize_t(strlen(name)) - 3;
    223             if ((index>0 && (index<SIZE-1)) && (!strcmp(name+index, "OES"))) {
    224                 strncpy(scrap, name, index);
    225                 scrap[index] = 0;
    226                 f = (__eglMustCastToProperFunctionPointerType)dlsym(dso, scrap);
    227                 //ALOGD_IF(f, "found <%s> instead", scrap);
    228             }
    229         }
    230         if (f == NULL) {
    231             // Try with the OES postfix
    232             ssize_t index = ssize_t(strlen(name)) - 3;
    233             if (index>0 && strcmp(name+index, "OES")) {
    234                 snprintf(scrap, SIZE, "%sOES", name);
    235                 f = (__eglMustCastToProperFunctionPointerType)dlsym(dso, scrap);
    236                 //ALOGD_IF(f, "found <%s> instead", scrap);
    237             }
    238         }
    239         if (f == NULL) {
    240             //ALOGD("%s", name);
    241             f = (__eglMustCastToProperFunctionPointerType)gl_unimplemented;
    242 
    243             /*
    244              * GL_EXT_debug_label is special, we always report it as
    245              * supported, it's handled by GLES_trace. If GLES_trace is not
    246              * enabled, then these are no-ops.
    247              */
    248             if (!strcmp(name, "glInsertEventMarkerEXT")) {
    249                 f = (__eglMustCastToProperFunctionPointerType)gl_noop;
    250             } else if (!strcmp(name, "glPushGroupMarkerEXT")) {
    251                 f = (__eglMustCastToProperFunctionPointerType)gl_noop;
    252             } else if (!strcmp(name, "glPopGroupMarkerEXT")) {
    253                 f = (__eglMustCastToProperFunctionPointerType)gl_noop;
    254             }
    255         }
    256         *curr++ = f;
    257         api++;
    258     }
    259 }
    260 
    261 void *Loader::load_driver(const char* kind,
    262         egl_connection_t* cnx, uint32_t mask)
    263 {
    264     class MatchFile {
    265     public:
    266         static String8 find(const char* kind) {
    267             String8 result;
    268             String8 pattern;
    269             pattern.appendFormat("lib%s", kind);
    270             const char* const searchPaths[] = {
    271                     "/vendor/lib/egl",
    272                     "/system/lib/egl"
    273             };
    274 
    275             // first, we search for the exact name of the GLES userspace
    276             // driver in both locations.
    277             // i.e.:
    278             //      libGLES.so, or:
    279             //      libEGL.so, libGLESv1_CM.so, libGLESv2.so
    280 
    281             for (size_t i=0 ; i<NELEM(searchPaths) ; i++) {
    282                 if (find(result, pattern, searchPaths[i], true)) {
    283                     return result;
    284                 }
    285             }
    286 
    287             // for compatibility with the old "egl.cfg" naming convention
    288             // we look for files that match:
    289             //      libGLES_*.so, or:
    290             //      libEGL_*.so, libGLESv1_CM_*.so, libGLESv2_*.so
    291 
    292             pattern.append("_");
    293             for (size_t i=0 ; i<NELEM(searchPaths) ; i++) {
    294                 if (find(result, pattern, searchPaths[i], false)) {
    295                     return result;
    296                 }
    297             }
    298 
    299             // we didn't find the driver. gah.
    300             result.clear();
    301             return result;
    302         }
    303 
    304     private:
    305         static bool find(String8& result,
    306                 const String8& pattern, const char* const search, bool exact) {
    307 
    308             // in the emulator case, we just return the hardcoded name
    309             // of the software renderer.
    310             if (checkGlesEmulationStatus() == 0) {
    311                 ALOGD("Emulator without GPU support detected. "
    312                       "Fallback to software renderer.");
    313                 result.setTo("/system/lib/egl/libGLES_android.so");
    314                 return true;
    315             }
    316 
    317             if (exact) {
    318                 String8 absolutePath;
    319                 absolutePath.appendFormat("%s/%s.so", search, pattern.string());
    320                 if (!access(absolutePath.string(), R_OK)) {
    321                     result = absolutePath;
    322                     return true;
    323                 }
    324                 return false;
    325             }
    326 
    327             DIR* d = opendir(search);
    328             if (d != NULL) {
    329                 struct dirent cur;
    330                 struct dirent* e;
    331                 while (readdir_r(d, &cur, &e) == 0 && e) {
    332                     if (e->d_type == DT_DIR) {
    333                         continue;
    334                     }
    335                     if (!strcmp(e->d_name, "libGLES_android.so")) {
    336                         // always skip the software renderer
    337                         continue;
    338                     }
    339                     if (strstr(e->d_name, pattern.string()) == e->d_name) {
    340                         if (!strcmp(e->d_name + strlen(e->d_name) - 3, ".so")) {
    341                             result.clear();
    342                             result.appendFormat("%s/%s", search, e->d_name);
    343                             closedir(d);
    344                             return true;
    345                         }
    346                     }
    347                 }
    348                 closedir(d);
    349             }
    350             return false;
    351         }
    352     };
    353 
    354 
    355     String8 absolutePath = MatchFile::find(kind);
    356     if (absolutePath.isEmpty()) {
    357         // this happens often, we don't want to log an error
    358         return 0;
    359     }
    360     const char* const driver_absolute_path = absolutePath.string();
    361 
    362     void* dso = dlopen(driver_absolute_path, RTLD_NOW | RTLD_LOCAL);
    363     if (dso == 0) {
    364         const char* err = dlerror();
    365         ALOGE("load_driver(%s): %s", driver_absolute_path, err?err:"unknown");
    366         return 0;
    367     }
    368 
    369     ALOGD("loaded %s", driver_absolute_path);
    370 
    371     if (mask & EGL) {
    372         getProcAddress = (getProcAddressType)dlsym(dso, "eglGetProcAddress");
    373 
    374         ALOGE_IF(!getProcAddress,
    375                 "can't find eglGetProcAddress() in %s", driver_absolute_path);
    376 
    377         egl_t* egl = &cnx->egl;
    378         __eglMustCastToProperFunctionPointerType* curr =
    379             (__eglMustCastToProperFunctionPointerType*)egl;
    380         char const * const * api = egl_names;
    381         while (*api) {
    382             char const * name = *api;
    383             __eglMustCastToProperFunctionPointerType f =
    384                 (__eglMustCastToProperFunctionPointerType)dlsym(dso, name);
    385             if (f == NULL) {
    386                 // couldn't find the entry-point, use eglGetProcAddress()
    387                 f = getProcAddress(name);
    388                 if (f == NULL) {
    389                     f = (__eglMustCastToProperFunctionPointerType)0;
    390                 }
    391             }
    392             *curr++ = f;
    393             api++;
    394         }
    395     }
    396 
    397     if (mask & GLESv1_CM) {
    398         init_api(dso, gl_names,
    399             (__eglMustCastToProperFunctionPointerType*)
    400                 &cnx->hooks[egl_connection_t::GLESv1_INDEX]->gl,
    401             getProcAddress);
    402     }
    403 
    404     if (mask & GLESv2) {
    405       init_api(dso, gl_names,
    406             (__eglMustCastToProperFunctionPointerType*)
    407                 &cnx->hooks[egl_connection_t::GLESv2_INDEX]->gl,
    408             getProcAddress);
    409     }
    410 
    411     return dso;
    412 }
    413 
    414 // ----------------------------------------------------------------------------
    415 }; // namespace android
    416 // ----------------------------------------------------------------------------
    417