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 <stdlib.h>
     18 
     19 #include <hardware/gralloc.h>
     20 
     21 #include <EGL/egl.h>
     22 
     23 #include <cutils/properties.h>
     24 
     25 #include <log/log.h>
     26 
     27 #include "../egl_impl.h"
     28 
     29 #include "egldefs.h"
     30 #include "egl_tls.h"
     31 #include "egl_display.h"
     32 #include "egl_object.h"
     33 #include "CallStack.h"
     34 #include "Loader.h"
     35 
     36 typedef __eglMustCastToProperFunctionPointerType EGLFuncPointer;
     37 
     38 // ----------------------------------------------------------------------------
     39 namespace android {
     40 // ----------------------------------------------------------------------------
     41 
     42 egl_connection_t gEGLImpl;
     43 gl_hooks_t gHooks[2];
     44 gl_hooks_t gHooksNoContext;
     45 pthread_key_t gGLWrapperKey = -1;
     46 
     47 // ----------------------------------------------------------------------------
     48 
     49 void setGLHooksThreadSpecific(gl_hooks_t const *value) {
     50     setGlThreadSpecific(value);
     51 }
     52 
     53 /*****************************************************************************/
     54 
     55 static int gl_no_context() {
     56     if (egl_tls_t::logNoContextCall()) {
     57         char const* const error = "call to OpenGL ES API with "
     58                 "no current context (logged once per thread)";
     59         if (LOG_NDEBUG) {
     60             ALOGE(error);
     61         } else {
     62             LOG_ALWAYS_FATAL(error);
     63         }
     64         char value[PROPERTY_VALUE_MAX];
     65         property_get("debug.egl.callstack", value, "0");
     66         if (atoi(value)) {
     67             CallStack::log(LOG_TAG);
     68         }
     69     }
     70     return 0;
     71 }
     72 
     73 static void early_egl_init(void)
     74 {
     75     int numHooks = sizeof(gHooksNoContext) / sizeof(EGLFuncPointer);
     76     EGLFuncPointer *iter = reinterpret_cast<EGLFuncPointer*>(&gHooksNoContext);
     77     for (int hook = 0; hook < numHooks; ++hook) {
     78         *(iter++) = reinterpret_cast<EGLFuncPointer>(gl_no_context);
     79     }
     80 
     81     setGLHooksThreadSpecific(&gHooksNoContext);
     82 }
     83 
     84 static pthread_once_t once_control = PTHREAD_ONCE_INIT;
     85 static int sEarlyInitState = pthread_once(&once_control, &early_egl_init);
     86 
     87 // ----------------------------------------------------------------------------
     88 
     89 egl_display_ptr validate_display(EGLDisplay dpy) {
     90     egl_display_ptr dp = get_display(dpy);
     91     if (!dp)
     92         return setError(EGL_BAD_DISPLAY, egl_display_ptr(NULL));
     93     if (!dp->isReady())
     94         return setError(EGL_NOT_INITIALIZED, egl_display_ptr(NULL));
     95 
     96     return dp;
     97 }
     98 
     99 egl_display_ptr validate_display_connection(EGLDisplay dpy,
    100         egl_connection_t*& cnx) {
    101     cnx = NULL;
    102     egl_display_ptr dp = validate_display(dpy);
    103     if (!dp)
    104         return dp;
    105     cnx = &gEGLImpl;
    106     if (cnx->dso == 0) {
    107         return setError(EGL_BAD_CONFIG, egl_display_ptr(NULL));
    108     }
    109     return dp;
    110 }
    111 
    112 // ----------------------------------------------------------------------------
    113 
    114 const GLubyte * egl_get_string_for_current_context(GLenum name) {
    115     // NOTE: returning NULL here will fall-back to the default
    116     // implementation.
    117 
    118     EGLContext context = egl_tls_t::getContext();
    119     if (context == EGL_NO_CONTEXT)
    120         return NULL;
    121 
    122     egl_context_t const * const c = get_context(context);
    123     if (c == NULL) // this should never happen, by construction
    124         return NULL;
    125 
    126     if (name != GL_EXTENSIONS)
    127         return NULL;
    128 
    129     return (const GLubyte *)c->gl_extensions.c_str();
    130 }
    131 
    132 const GLubyte * egl_get_string_for_current_context(GLenum name, GLuint index) {
    133     // NOTE: returning NULL here will fall-back to the default
    134     // implementation.
    135 
    136     EGLContext context = egl_tls_t::getContext();
    137     if (context == EGL_NO_CONTEXT)
    138         return NULL;
    139 
    140     egl_context_t const * const c = get_context(context);
    141     if (c == NULL) // this should never happen, by construction
    142         return NULL;
    143 
    144     if (name != GL_EXTENSIONS)
    145         return NULL;
    146 
    147     // if index is out of bounds, assume it will be in the default
    148     // implementation too, so we don't have to generate a GL error here
    149     if (index >= c->tokenized_gl_extensions.size())
    150         return NULL;
    151 
    152     return (const GLubyte *)c->tokenized_gl_extensions[index].c_str();
    153 }
    154 
    155 GLint egl_get_num_extensions_for_current_context() {
    156     // NOTE: returning -1 here will fall-back to the default
    157     // implementation.
    158 
    159     EGLContext context = egl_tls_t::getContext();
    160     if (context == EGL_NO_CONTEXT)
    161         return -1;
    162 
    163     egl_context_t const * const c = get_context(context);
    164     if (c == NULL) // this should never happen, by construction
    165         return -1;
    166 
    167     return (GLint)c->tokenized_gl_extensions.size();
    168 }
    169 
    170 // ----------------------------------------------------------------------------
    171 
    172 // this mutex protects:
    173 //    d->disp[]
    174 //    egl_init_drivers_locked()
    175 //
    176 static EGLBoolean egl_init_drivers_locked() {
    177     if (sEarlyInitState) {
    178         // initialized by static ctor. should be set here.
    179         return EGL_FALSE;
    180     }
    181 
    182     // get our driver loader
    183     Loader& loader(Loader::getInstance());
    184 
    185     // dynamically load our EGL implementation
    186     egl_connection_t* cnx = &gEGLImpl;
    187     if (cnx->dso == 0) {
    188         cnx->hooks[egl_connection_t::GLESv1_INDEX] =
    189                 &gHooks[egl_connection_t::GLESv1_INDEX];
    190         cnx->hooks[egl_connection_t::GLESv2_INDEX] =
    191                 &gHooks[egl_connection_t::GLESv2_INDEX];
    192         cnx->dso = loader.open(cnx);
    193     }
    194 
    195     return cnx->dso ? EGL_TRUE : EGL_FALSE;
    196 }
    197 
    198 static pthread_mutex_t sInitDriverMutex = PTHREAD_MUTEX_INITIALIZER;
    199 
    200 EGLBoolean egl_init_drivers() {
    201     EGLBoolean res;
    202     pthread_mutex_lock(&sInitDriverMutex);
    203     res = egl_init_drivers_locked();
    204     pthread_mutex_unlock(&sInitDriverMutex);
    205     return res;
    206 }
    207 
    208 static pthread_mutex_t sLogPrintMutex = PTHREAD_MUTEX_INITIALIZER;
    209 static std::chrono::steady_clock::time_point sLogPrintTime;
    210 static constexpr std::chrono::seconds DURATION(1);
    211 
    212 void gl_unimplemented() {
    213     bool printLog = false;
    214     auto now = std::chrono::steady_clock::now();
    215     pthread_mutex_lock(&sLogPrintMutex);
    216     if ((now - sLogPrintTime) > DURATION) {
    217         sLogPrintTime = now;
    218         printLog = true;
    219     }
    220     pthread_mutex_unlock(&sLogPrintMutex);
    221     if (printLog) {
    222         ALOGE("called unimplemented OpenGL ES API");
    223         char value[PROPERTY_VALUE_MAX];
    224         property_get("debug.egl.callstack", value, "0");
    225         if (atoi(value)) {
    226             CallStack::log(LOG_TAG);
    227         }
    228     }
    229 }
    230 
    231 void gl_noop() {
    232 }
    233 
    234 // ----------------------------------------------------------------------------
    235 
    236 void setGlThreadSpecific(gl_hooks_t const *value) {
    237     gl_hooks_t const * volatile * tls_hooks = get_tls_hooks();
    238     tls_hooks[TLS_SLOT_OPENGL_API] = value;
    239 }
    240 
    241 // ----------------------------------------------------------------------------
    242 // GL / EGL hooks
    243 // ----------------------------------------------------------------------------
    244 
    245 #undef GL_ENTRY
    246 #undef EGL_ENTRY
    247 #define GL_ENTRY(_r, _api, ...) #_api,
    248 #define EGL_ENTRY(_r, _api, ...) #_api,
    249 
    250 char const * const gl_names[] = {
    251     #include "../entries.in"
    252     NULL
    253 };
    254 
    255 char const * const egl_names[] = {
    256     #include "egl_entries.in"
    257     NULL
    258 };
    259 
    260 #undef GL_ENTRY
    261 #undef EGL_ENTRY
    262 
    263 
    264 // ----------------------------------------------------------------------------
    265 }; // namespace android
    266 // ----------------------------------------------------------------------------
    267 
    268