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 #define __STDC_LIMIT_MACROS 1
     18 
     19 #include <string.h>
     20 
     21 #include "egl_cache.h"
     22 #include "egl_display.h"
     23 #include "egl_object.h"
     24 #include "egl_tls.h"
     25 #include "egl_impl.h"
     26 #include "Loader.h"
     27 #include <cutils/properties.h>
     28 
     29 // ----------------------------------------------------------------------------
     30 namespace android {
     31 // ----------------------------------------------------------------------------
     32 
     33 static char const * const sVendorString     = "Android";
     34 static char const * const sVersionString    = "1.4 Android META-EGL";
     35 static char const * const sClientApiString  = "OpenGL_ES";
     36 
     37 // this is the list of EGL extensions that are exposed to applications
     38 // some of them are mandatory because used by the ANDROID system.
     39 //
     40 // mandatory extensions are required per the CDD and not explicitly
     41 // checked during EGL initialization. the system *assumes* these extensions
     42 // are present. the system may not function properly if some mandatory
     43 // extensions are missing.
     44 //
     45 // NOTE: sExtensionString MUST be have a single space as the last character.
     46 //
     47 static char const * const sExtensionString  =
     48         "EGL_KHR_image "                        // mandatory
     49         "EGL_KHR_image_base "                   // mandatory
     50         "EGL_KHR_image_pixmap "
     51         "EGL_KHR_gl_texture_2D_image "
     52         "EGL_KHR_gl_texture_cubemap_image "
     53         "EGL_KHR_gl_renderbuffer_image "
     54         "EGL_KHR_fence_sync "
     55         "EGL_NV_system_time "
     56         "EGL_ANDROID_image_native_buffer "      // mandatory
     57         ;
     58 
     59 // extensions not exposed to applications but used by the ANDROID system
     60 //      "EGL_ANDROID_recordable "               // mandatory
     61 //      "EGL_ANDROID_blob_cache "               // strongly recommended
     62 //      "EGL_IMG_hibernate_process "            // optional
     63 
     64 extern void initEglTraceLevel();
     65 extern void initEglDebugLevel();
     66 extern void setGLHooksThreadSpecific(gl_hooks_t const *value);
     67 
     68 // ----------------------------------------------------------------------------
     69 
     70 egl_display_t egl_display_t::sDisplay[NUM_DISPLAYS];
     71 
     72 egl_display_t::egl_display_t() :
     73     magic('_dpy'), finishOnSwap(false), traceGpuCompletion(false), refs(0) {
     74 }
     75 
     76 egl_display_t::~egl_display_t() {
     77     magic = 0;
     78     egl_cache_t::get()->terminate();
     79 }
     80 
     81 egl_display_t* egl_display_t::get(EGLDisplay dpy) {
     82     uintptr_t index = uintptr_t(dpy)-1U;
     83     return (index >= NUM_DISPLAYS) ? NULL : &sDisplay[index];
     84 }
     85 
     86 void egl_display_t::addObject(egl_object_t* object) {
     87     Mutex::Autolock _l(lock);
     88     objects.add(object);
     89 }
     90 
     91 void egl_display_t::removeObject(egl_object_t* object) {
     92     Mutex::Autolock _l(lock);
     93     objects.remove(object);
     94 }
     95 
     96 bool egl_display_t::getObject(egl_object_t* object) const {
     97     Mutex::Autolock _l(lock);
     98     if (objects.indexOf(object) >= 0) {
     99         if (object->getDisplay() == this) {
    100             object->incRef();
    101             return true;
    102         }
    103     }
    104     return false;
    105 }
    106 
    107 EGLDisplay egl_display_t::getFromNativeDisplay(EGLNativeDisplayType disp) {
    108     if (uintptr_t(disp) >= NUM_DISPLAYS)
    109         return NULL;
    110 
    111     return sDisplay[uintptr_t(disp)].getDisplay(disp);
    112 }
    113 
    114 EGLDisplay egl_display_t::getDisplay(EGLNativeDisplayType display) {
    115 
    116     Mutex::Autolock _l(lock);
    117 
    118     // get our driver loader
    119     Loader& loader(Loader::getInstance());
    120 
    121     egl_connection_t* const cnx = &gEGLImpl;
    122     if (cnx->dso && disp.dpy == EGL_NO_DISPLAY) {
    123         EGLDisplay dpy = cnx->egl.eglGetDisplay(display);
    124         disp.dpy = dpy;
    125         if (dpy == EGL_NO_DISPLAY) {
    126             loader.close(cnx->dso);
    127             cnx->dso = NULL;
    128         }
    129     }
    130 
    131     return EGLDisplay(uintptr_t(display) + 1U);
    132 }
    133 
    134 EGLBoolean egl_display_t::initialize(EGLint *major, EGLint *minor) {
    135 
    136     Mutex::Autolock _l(lock);
    137 
    138     if (refs > 0) {
    139         if (major != NULL)
    140             *major = VERSION_MAJOR;
    141         if (minor != NULL)
    142             *minor = VERSION_MINOR;
    143         refs++;
    144         return EGL_TRUE;
    145     }
    146 
    147 #if EGL_TRACE
    148 
    149     // Called both at early_init time and at this time. (Early_init is pre-zygote, so
    150     // the information from that call may be stale.)
    151     initEglTraceLevel();
    152     initEglDebugLevel();
    153 
    154 #endif
    155 
    156     setGLHooksThreadSpecific(&gHooksNoContext);
    157 
    158     // initialize each EGL and
    159     // build our own extension string first, based on the extension we know
    160     // and the extension supported by our client implementation
    161 
    162     egl_connection_t* const cnx = &gEGLImpl;
    163     cnx->major = -1;
    164     cnx->minor = -1;
    165     if (cnx->dso) {
    166 
    167 #if defined(ADRENO130)
    168 #warning "Adreno-130 eglInitialize() workaround"
    169         /*
    170          * The ADRENO 130 driver returns a different EGLDisplay each time
    171          * eglGetDisplay() is called, but also makes the EGLDisplay invalid
    172          * after eglTerminate() has been called, so that eglInitialize()
    173          * cannot be called again. Therefore, we need to make sure to call
    174          * eglGetDisplay() before calling eglInitialize();
    175          */
    176         if (i == IMPL_HARDWARE) {
    177             disp[i].dpy = cnx->egl.eglGetDisplay(EGL_DEFAULT_DISPLAY);
    178         }
    179 #endif
    180 
    181         EGLDisplay idpy = disp.dpy;
    182         if (cnx->egl.eglInitialize(idpy, &cnx->major, &cnx->minor)) {
    183             //ALOGD("initialized dpy=%p, ver=%d.%d, cnx=%p",
    184             //        idpy, cnx->major, cnx->minor, cnx);
    185 
    186             // display is now initialized
    187             disp.state = egl_display_t::INITIALIZED;
    188 
    189             // get the query-strings for this display for each implementation
    190             disp.queryString.vendor = cnx->egl.eglQueryString(idpy,
    191                     EGL_VENDOR);
    192             disp.queryString.version = cnx->egl.eglQueryString(idpy,
    193                     EGL_VERSION);
    194             disp.queryString.extensions = cnx->egl.eglQueryString(idpy,
    195                     EGL_EXTENSIONS);
    196             disp.queryString.clientApi = cnx->egl.eglQueryString(idpy,
    197                     EGL_CLIENT_APIS);
    198 
    199         } else {
    200             ALOGW("eglInitialize(%p) failed (%s)", idpy,
    201                     egl_tls_t::egl_strerror(cnx->egl.eglGetError()));
    202         }
    203     }
    204 
    205     // the query strings are per-display
    206     mVendorString.setTo(sVendorString);
    207     mVersionString.setTo(sVersionString);
    208     mClientApiString.setTo(sClientApiString);
    209 
    210     // we only add extensions that exist in the implementation
    211     char const* start = sExtensionString;
    212     char const* end;
    213     do {
    214         // find the space separating this extension for the next one
    215         end = strchr(start, ' ');
    216         if (end) {
    217             // length of the extension string
    218             const size_t len = end - start;
    219             if (len) {
    220                 // NOTE: we could avoid the copy if we had strnstr.
    221                 const String8 ext(start, len);
    222                 // now look for this extension
    223                 if (disp.queryString.extensions) {
    224                     // if we find it, add this extension string to our list
    225                     // (and don't forget the space)
    226                     const char* match = strstr(disp.queryString.extensions, ext.string());
    227                     if (match && (match[len] == ' ' || match[len] == 0)) {
    228                         mExtensionString.append(start, len+1);
    229                     }
    230                 }
    231             }
    232             // process the next extension string, and skip the space.
    233             start = end + 1;
    234         }
    235     } while (end);
    236 
    237     egl_cache_t::get()->initialize(this);
    238 
    239     char value[PROPERTY_VALUE_MAX];
    240     property_get("debug.egl.finish", value, "0");
    241     if (atoi(value)) {
    242         finishOnSwap = true;
    243     }
    244 
    245     property_get("debug.egl.traceGpuCompletion", value, "0");
    246     if (atoi(value)) {
    247         traceGpuCompletion = true;
    248     }
    249 
    250     refs++;
    251     if (major != NULL)
    252         *major = VERSION_MAJOR;
    253     if (minor != NULL)
    254         *minor = VERSION_MINOR;
    255 
    256     mHibernation.setDisplayValid(true);
    257 
    258     return EGL_TRUE;
    259 }
    260 
    261 EGLBoolean egl_display_t::terminate() {
    262 
    263     Mutex::Autolock _l(lock);
    264 
    265     if (refs == 0) {
    266         return setError(EGL_NOT_INITIALIZED, EGL_FALSE);
    267     }
    268 
    269     // this is specific to Android, display termination is ref-counted.
    270     if (refs > 1) {
    271         refs--;
    272         return EGL_TRUE;
    273     }
    274 
    275     EGLBoolean res = EGL_FALSE;
    276     egl_connection_t* const cnx = &gEGLImpl;
    277     if (cnx->dso && disp.state == egl_display_t::INITIALIZED) {
    278         if (cnx->egl.eglTerminate(disp.dpy) == EGL_FALSE) {
    279             ALOGW("eglTerminate(%p) failed (%s)", disp.dpy,
    280                     egl_tls_t::egl_strerror(cnx->egl.eglGetError()));
    281         }
    282         // REVISIT: it's unclear what to do if eglTerminate() fails
    283         disp.state = egl_display_t::TERMINATED;
    284         res = EGL_TRUE;
    285     }
    286 
    287     mHibernation.setDisplayValid(false);
    288 
    289     // Mark all objects remaining in the list as terminated, unless
    290     // there are no reference to them, it which case, we're free to
    291     // delete them.
    292     size_t count = objects.size();
    293     ALOGW_IF(count, "eglTerminate() called w/ %d objects remaining", count);
    294     for (size_t i=0 ; i<count ; i++) {
    295         egl_object_t* o = objects.itemAt(i);
    296         o->destroy();
    297     }
    298 
    299     // this marks all object handles are "terminated"
    300     objects.clear();
    301 
    302     refs--;
    303     return res;
    304 }
    305 
    306 void egl_display_t::loseCurrent(egl_context_t * cur_c)
    307 {
    308     if (cur_c) {
    309         egl_display_t* display = cur_c->getDisplay();
    310         if (display) {
    311             display->loseCurrentImpl(cur_c);
    312         }
    313     }
    314 }
    315 
    316 void egl_display_t::loseCurrentImpl(egl_context_t * cur_c)
    317 {
    318     // by construction, these are either 0 or valid (possibly terminated)
    319     // it should be impossible for these to be invalid
    320     ContextRef _cur_c(cur_c);
    321     SurfaceRef _cur_r(cur_c ? get_surface(cur_c->read) : NULL);
    322     SurfaceRef _cur_d(cur_c ? get_surface(cur_c->draw) : NULL);
    323 
    324     { // scope for the lock
    325         Mutex::Autolock _l(lock);
    326         cur_c->onLooseCurrent();
    327 
    328     }
    329 
    330     // This cannot be called with the lock held because it might end-up
    331     // calling back into EGL (in particular when a surface is destroyed
    332     // it calls ANativeWindow::disconnect
    333     _cur_c.release();
    334     _cur_r.release();
    335     _cur_d.release();
    336 }
    337 
    338 EGLBoolean egl_display_t::makeCurrent(egl_context_t* c, egl_context_t* cur_c,
    339         EGLSurface draw, EGLSurface read, EGLContext ctx,
    340         EGLSurface impl_draw, EGLSurface impl_read, EGLContext impl_ctx)
    341 {
    342     EGLBoolean result;
    343 
    344     // by construction, these are either 0 or valid (possibly terminated)
    345     // it should be impossible for these to be invalid
    346     ContextRef _cur_c(cur_c);
    347     SurfaceRef _cur_r(cur_c ? get_surface(cur_c->read) : NULL);
    348     SurfaceRef _cur_d(cur_c ? get_surface(cur_c->draw) : NULL);
    349 
    350     { // scope for the lock
    351         Mutex::Autolock _l(lock);
    352         if (c) {
    353             result = c->cnx->egl.eglMakeCurrent(
    354                     disp.dpy, impl_draw, impl_read, impl_ctx);
    355             if (result == EGL_TRUE) {
    356                 c->onMakeCurrent(draw, read);
    357                 if (!cur_c) {
    358                     mHibernation.incWakeCount(HibernationMachine::STRONG);
    359                 }
    360             }
    361         } else {
    362             result = cur_c->cnx->egl.eglMakeCurrent(
    363                     disp.dpy, impl_draw, impl_read, impl_ctx);
    364             if (result == EGL_TRUE) {
    365                 cur_c->onLooseCurrent();
    366                 mHibernation.decWakeCount(HibernationMachine::STRONG);
    367             }
    368         }
    369     }
    370 
    371     if (result == EGL_TRUE) {
    372         // This cannot be called with the lock held because it might end-up
    373         // calling back into EGL (in particular when a surface is destroyed
    374         // it calls ANativeWindow::disconnect
    375         _cur_c.release();
    376         _cur_r.release();
    377         _cur_d.release();
    378     }
    379 
    380     return result;
    381 }
    382 
    383 // ----------------------------------------------------------------------------
    384 
    385 bool egl_display_t::HibernationMachine::incWakeCount(WakeRefStrength strength) {
    386     Mutex::Autolock _l(mLock);
    387     ALOGE_IF(mWakeCount < 0 || mWakeCount == INT32_MAX,
    388              "Invalid WakeCount (%d) on enter\n", mWakeCount);
    389 
    390     mWakeCount++;
    391     if (strength == STRONG)
    392         mAttemptHibernation = false;
    393 
    394     if (CC_UNLIKELY(mHibernating)) {
    395         ALOGV("Awakening\n");
    396         egl_connection_t* const cnx = &gEGLImpl;
    397 
    398         // These conditions should be guaranteed before entering hibernation;
    399         // we don't want to get into a state where we can't wake up.
    400         ALOGD_IF(!mDpyValid || !cnx->egl.eglAwakenProcessIMG,
    401                  "Invalid hibernation state, unable to awaken\n");
    402 
    403         if (!cnx->egl.eglAwakenProcessIMG()) {
    404             ALOGE("Failed to awaken EGL implementation\n");
    405             return false;
    406         }
    407         mHibernating = false;
    408     }
    409     return true;
    410 }
    411 
    412 void egl_display_t::HibernationMachine::decWakeCount(WakeRefStrength strength) {
    413     Mutex::Autolock _l(mLock);
    414     ALOGE_IF(mWakeCount <= 0, "Invalid WakeCount (%d) on leave\n", mWakeCount);
    415 
    416     mWakeCount--;
    417     if (strength == STRONG)
    418         mAttemptHibernation = true;
    419 
    420     if (mWakeCount == 0 && CC_UNLIKELY(mAttemptHibernation)) {
    421         egl_connection_t* const cnx = &gEGLImpl;
    422         mAttemptHibernation = false;
    423         if (mAllowHibernation && mDpyValid &&
    424                 cnx->egl.eglHibernateProcessIMG &&
    425                 cnx->egl.eglAwakenProcessIMG) {
    426             ALOGV("Hibernating\n");
    427             if (!cnx->egl.eglHibernateProcessIMG()) {
    428                 ALOGE("Failed to hibernate EGL implementation\n");
    429                 return;
    430             }
    431             mHibernating = true;
    432         }
    433     }
    434 }
    435 
    436 void egl_display_t::HibernationMachine::setDisplayValid(bool valid) {
    437     Mutex::Autolock _l(mLock);
    438     mDpyValid = valid;
    439 }
    440 
    441 // ----------------------------------------------------------------------------
    442 }; // namespace android
    443 // ----------------------------------------------------------------------------
    444