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