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 <string.h>
     18 
     19 #include "egl_cache.h"
     20 #include "egl_display.h"
     21 #include "egl_object.h"
     22 #include "egl_tls.h"
     23 #include "egl_impl.h"
     24 #include "Loader.h"
     25 
     26 // ----------------------------------------------------------------------------
     27 namespace android {
     28 // ----------------------------------------------------------------------------
     29 
     30 static char const * const sVendorString     = "Android";
     31 static char const * const sVersionString    = "1.4 Android META-EGL";
     32 static char const * const sClientApiString  = "OpenGL ES";
     33 
     34 // this is the list of EGL extensions that are exposed to applications
     35 // some of them are mandatory because used by the ANDROID system.
     36 //
     37 // mandatory extensions are required per the CDD and not explicitly
     38 // checked during EGL initialization. the system *assumes* these extensions
     39 // are present. the system may not function properly if some mandatory
     40 // extensions are missing.
     41 //
     42 // NOTE: sExtensionString MUST be have a single space as the last character.
     43 //
     44 static char const * const sExtensionString  =
     45         "EGL_KHR_image "                        // mandatory
     46         "EGL_KHR_image_base "                   // mandatory
     47         "EGL_KHR_image_pixmap "
     48         "EGL_KHR_gl_texture_2D_image "
     49         "EGL_KHR_gl_texture_cubemap_image "
     50         "EGL_KHR_gl_renderbuffer_image "
     51         "EGL_KHR_fence_sync "
     52         "EGL_NV_system_time "
     53         "EGL_ANDROID_image_native_buffer "      // mandatory
     54         ;
     55 
     56 // extensions not exposed to applications but used by the ANDROID system
     57 //      "EGL_ANDROID_recordable "               // mandatory
     58 //      "EGL_ANDROID_blob_cache "               // strongly recommended
     59 
     60 extern void initEglTraceLevel();
     61 extern void setGLHooksThreadSpecific(gl_hooks_t const *value);
     62 
     63 static int cmp_configs(const void* a, const void *b) {
     64     const egl_config_t& c0 = *(egl_config_t const *)a;
     65     const egl_config_t& c1 = *(egl_config_t const *)b;
     66     return c0<c1 ? -1 : (c1<c0 ? 1 : 0);
     67 }
     68 
     69 // ----------------------------------------------------------------------------
     70 
     71 egl_display_t egl_display_t::sDisplay[NUM_DISPLAYS];
     72 
     73 egl_display_t::egl_display_t() :
     74     magic('_dpy'), numTotalConfigs(0), configs(0), refs(0) {
     75 }
     76 
     77 egl_display_t::~egl_display_t() {
     78     magic = 0;
     79     egl_cache_t::get()->terminate();
     80 }
     81 
     82 egl_display_t* egl_display_t::get(EGLDisplay dpy) {
     83     uintptr_t index = uintptr_t(dpy)-1U;
     84     return (index >= NUM_DISPLAYS) ? NULL : &sDisplay[index];
     85 }
     86 
     87 void egl_display_t::addObject(egl_object_t* object) {
     88     Mutex::Autolock _l(lock);
     89     objects.add(object);
     90 }
     91 
     92 void egl_display_t::removeObject(egl_object_t* object) {
     93     Mutex::Autolock _l(lock);
     94     objects.remove(object);
     95 }
     96 
     97 bool egl_display_t::getObject(egl_object_t* object) const {
     98     Mutex::Autolock _l(lock);
     99     if (objects.indexOf(object) >= 0) {
    100         if (object->getDisplay() == this) {
    101             object->incRef();
    102             return true;
    103         }
    104     }
    105     return false;
    106 }
    107 
    108 EGLDisplay egl_display_t::getFromNativeDisplay(EGLNativeDisplayType disp) {
    109     if (uintptr_t(disp) >= NUM_DISPLAYS)
    110         return NULL;
    111 
    112     return sDisplay[uintptr_t(disp)].getDisplay(disp);
    113 }
    114 
    115 EGLDisplay egl_display_t::getDisplay(EGLNativeDisplayType display) {
    116 
    117     Mutex::Autolock _l(lock);
    118 
    119     // get our driver loader
    120     Loader& loader(Loader::getInstance());
    121 
    122     for (int i = 0; i < IMPL_NUM_IMPLEMENTATIONS; i++) {
    123         egl_connection_t* const cnx = &gEGLImpl[i];
    124         if (cnx->dso && disp[i].dpy == EGL_NO_DISPLAY) {
    125             EGLDisplay dpy = cnx->egl.eglGetDisplay(display);
    126             disp[i].dpy = dpy;
    127             if (dpy == EGL_NO_DISPLAY) {
    128                 loader.close(cnx->dso);
    129                 cnx->dso = NULL;
    130             }
    131         }
    132     }
    133 
    134     return EGLDisplay(uintptr_t(display) + 1U);
    135 }
    136 
    137 EGLBoolean egl_display_t::initialize(EGLint *major, EGLint *minor) {
    138 
    139     Mutex::Autolock _l(lock);
    140 
    141     if (refs > 0) {
    142         if (major != NULL)
    143             *major = VERSION_MAJOR;
    144         if (minor != NULL)
    145             *minor = VERSION_MINOR;
    146         refs++;
    147         return EGL_TRUE;
    148     }
    149 
    150 #if EGL_TRACE
    151 
    152     // Called both at early_init time and at this time. (Early_init is pre-zygote, so
    153     // the information from that call may be stale.)
    154     initEglTraceLevel();
    155 
    156 #endif
    157 
    158     setGLHooksThreadSpecific(&gHooksNoContext);
    159 
    160     // initialize each EGL and
    161     // build our own extension string first, based on the extension we know
    162     // and the extension supported by our client implementation
    163     for (int i = 0; i < IMPL_NUM_IMPLEMENTATIONS; i++) {
    164         egl_connection_t* const cnx = &gEGLImpl[i];
    165         cnx->major = -1;
    166         cnx->minor = -1;
    167         if (!cnx->dso)
    168             continue;
    169 
    170 #if defined(ADRENO130)
    171 #warning "Adreno-130 eglInitialize() workaround"
    172         /*
    173          * The ADRENO 130 driver returns a different EGLDisplay each time
    174          * eglGetDisplay() is called, but also makes the EGLDisplay invalid
    175          * after eglTerminate() has been called, so that eglInitialize()
    176          * cannot be called again. Therefore, we need to make sure to call
    177          * eglGetDisplay() before calling eglInitialize();
    178          */
    179         if (i == IMPL_HARDWARE) {
    180             disp[i].dpy =
    181             cnx->egl.eglGetDisplay(EGL_DEFAULT_DISPLAY);
    182         }
    183 #endif
    184 
    185         EGLDisplay idpy = disp[i].dpy;
    186         if (cnx->egl.eglInitialize(idpy, &cnx->major, &cnx->minor)) {
    187             //LOGD("initialized %d dpy=%p, ver=%d.%d, cnx=%p",
    188             //        i, idpy, cnx->major, cnx->minor, cnx);
    189 
    190             // display is now initialized
    191             disp[i].state = egl_display_t::INITIALIZED;
    192 
    193             // get the query-strings for this display for each implementation
    194             disp[i].queryString.vendor = cnx->egl.eglQueryString(idpy,
    195                     EGL_VENDOR);
    196             disp[i].queryString.version = cnx->egl.eglQueryString(idpy,
    197                     EGL_VERSION);
    198             disp[i].queryString.extensions = cnx->egl.eglQueryString(idpy,
    199                     EGL_EXTENSIONS);
    200             disp[i].queryString.clientApi = cnx->egl.eglQueryString(idpy,
    201                     EGL_CLIENT_APIS);
    202 
    203         } else {
    204             LOGW("%d: eglInitialize(%p) failed (%s)", i, idpy,
    205                     egl_tls_t::egl_strerror(cnx->egl.eglGetError()));
    206         }
    207     }
    208 
    209     // the query strings are per-display
    210     mVendorString.setTo(sVendorString);
    211     mVersionString.setTo(sVersionString);
    212     mClientApiString.setTo(sClientApiString);
    213 
    214     // we only add extensions that exist in at least one implementation
    215     char const* start = sExtensionString;
    216     char const* end;
    217     do {
    218         // find the space separating this extension for the next one
    219         end = strchr(start, ' ');
    220         if (end) {
    221             // length of the extension string
    222             const size_t len = end - start;
    223             if (len) {
    224                 // NOTE: we could avoid the copy if we had strnstr.
    225                 const String8 ext(start, len);
    226                 // now go through all implementations and look for this extension
    227                 for (int i = 0; i < IMPL_NUM_IMPLEMENTATIONS; i++) {
    228                     if (disp[i].queryString.extensions) {
    229                         // if we find it, add this extension string to our list
    230                         // (and don't forget the space)
    231                         const char* match = strstr(disp[i].queryString.extensions, ext.string());
    232                         if (match && (match[len] == ' ' || match[len] == 0)) {
    233                             mExtensionString.append(start, len+1);
    234                         }
    235                     }
    236                 }
    237             }
    238             // process the next extension string, and skip the space.
    239             start = end + 1;
    240         }
    241     } while (end);
    242 
    243     egl_cache_t::get()->initialize(this);
    244 
    245     EGLBoolean res = EGL_FALSE;
    246     for (int i = 0; i < IMPL_NUM_IMPLEMENTATIONS; i++) {
    247         egl_connection_t* const cnx = &gEGLImpl[i];
    248         if (cnx->dso && cnx->major >= 0 && cnx->minor >= 0) {
    249             EGLint n;
    250             if (cnx->egl.eglGetConfigs(disp[i].dpy, 0, 0, &n)) {
    251                 disp[i].config = (EGLConfig*) malloc(sizeof(EGLConfig) * n);
    252                 if (disp[i].config) {
    253                     if (cnx->egl.eglGetConfigs(disp[i].dpy, disp[i].config, n,
    254                             &disp[i].numConfigs)) {
    255                         numTotalConfigs += n;
    256                         res = EGL_TRUE;
    257                     }
    258                 }
    259             }
    260         }
    261     }
    262 
    263     if (res == EGL_TRUE) {
    264         configs = new egl_config_t[numTotalConfigs];
    265         for (int i = 0, k = 0; i < IMPL_NUM_IMPLEMENTATIONS; i++) {
    266             egl_connection_t* const cnx = &gEGLImpl[i];
    267             if (cnx->dso && cnx->major >= 0 && cnx->minor >= 0) {
    268                 for (int j = 0; j < disp[i].numConfigs; j++) {
    269                     configs[k].impl = i;
    270                     configs[k].config = disp[i].config[j];
    271                     configs[k].configId = k + 1; // CONFIG_ID start at 1
    272                     // store the implementation's CONFIG_ID
    273                     cnx->egl.eglGetConfigAttrib(disp[i].dpy, disp[i].config[j],
    274                             EGL_CONFIG_ID, &configs[k].implConfigId);
    275                     k++;
    276                 }
    277             }
    278         }
    279 
    280         // sort our configurations so we can do binary-searches
    281         qsort(configs, numTotalConfigs, sizeof(egl_config_t), cmp_configs);
    282 
    283         refs++;
    284         if (major != NULL)
    285             *major = VERSION_MAJOR;
    286         if (minor != NULL)
    287             *minor = VERSION_MINOR;
    288         return EGL_TRUE;
    289     }
    290     return setError(EGL_NOT_INITIALIZED, EGL_FALSE);
    291 }
    292 
    293 EGLBoolean egl_display_t::terminate() {
    294 
    295     Mutex::Autolock _l(lock);
    296 
    297     if (refs == 0) {
    298         return setError(EGL_NOT_INITIALIZED, EGL_FALSE);
    299     }
    300 
    301     // this is specific to Android, display termination is ref-counted.
    302     if (refs > 1) {
    303         refs--;
    304         return EGL_TRUE;
    305     }
    306 
    307     EGLBoolean res = EGL_FALSE;
    308     for (int i = 0; i < IMPL_NUM_IMPLEMENTATIONS; i++) {
    309         egl_connection_t* const cnx = &gEGLImpl[i];
    310         if (cnx->dso && disp[i].state == egl_display_t::INITIALIZED) {
    311             if (cnx->egl.eglTerminate(disp[i].dpy) == EGL_FALSE) {
    312                 LOGW("%d: eglTerminate(%p) failed (%s)", i, disp[i].dpy,
    313                         egl_tls_t::egl_strerror(cnx->egl.eglGetError()));
    314             }
    315             // REVISIT: it's unclear what to do if eglTerminate() fails
    316             free(disp[i].config);
    317 
    318             disp[i].numConfigs = 0;
    319             disp[i].config = 0;
    320             disp[i].state = egl_display_t::TERMINATED;
    321 
    322             res = EGL_TRUE;
    323         }
    324     }
    325 
    326     // Mark all objects remaining in the list as terminated, unless
    327     // there are no reference to them, it which case, we're free to
    328     // delete them.
    329     size_t count = objects.size();
    330     LOGW_IF(count, "eglTerminate() called w/ %d objects remaining", count);
    331     for (size_t i=0 ; i<count ; i++) {
    332         egl_object_t* o = objects.itemAt(i);
    333         o->destroy();
    334     }
    335 
    336     // this marks all object handles are "terminated"
    337     objects.clear();
    338 
    339     refs--;
    340     numTotalConfigs = 0;
    341     delete[] configs;
    342     return res;
    343 }
    344 
    345 
    346 // ----------------------------------------------------------------------------
    347 }; // namespace android
    348 // ----------------------------------------------------------------------------
    349