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