• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include <GLES/gl.h>
27 #include <GLES/glext.h>
28 
29 #include <cutils/log.h>
30 #include <cutils/atomic.h>
31 #include <cutils/properties.h>
32 #include <cutils/memory.h>
33 
34 #include <utils/CallStack.h>
35 #include <utils/String8.h>
36 
37 #include "egldefs.h"
38 #include "egl_impl.h"
39 #include "egl_tls.h"
40 #include "glestrace.h"
41 #include "hooks.h"
42 #include "Loader.h"
43 
44 #include "egl_display.h"
45 #include "egl_object.h"
46 
47 // ----------------------------------------------------------------------------
48 namespace android {
49 // ----------------------------------------------------------------------------
50 
51 egl_connection_t gEGLImpl;
52 gl_hooks_t gHooks[2];
53 gl_hooks_t gHooksNoContext;
54 pthread_key_t gGLWrapperKey = -1;
55 
56 // ----------------------------------------------------------------------------
57 
58 #if EGL_TRACE
59 
60 EGLAPI pthread_key_t gGLTraceKey = -1;
61 
62 // ----------------------------------------------------------------------------
63 
64 /**
65  * There are three different tracing methods:
66  * 1. libs/EGL/trace.cpp: Traces all functions to systrace.
67  *    To enable:
68  *      - set system property "debug.egl.trace" to "systrace" to trace all apps.
69  * 2. libs/EGL/trace.cpp: Logs a stack trace for GL errors after each function call.
70  *    To enable:
71  *      - set system property "debug.egl.trace" to "error" to trace all apps.
72  * 3. libs/EGL/trace.cpp: Traces all functions to logcat.
73  *    To enable:
74  *      - set system property "debug.egl.trace" to 1 to trace all apps.
75  *      - or call setGLTraceLevel(1) from an app to enable tracing for that app.
76  * 4. libs/GLES_trace: Traces all functions via protobuf to host.
77  *    To enable:
78  *        - set system property "debug.egl.debug_proc" to the application name.
79  *      - or call setGLDebugLevel(1) from the app.
80  */
81 static int sEGLTraceLevel;
82 static int sEGLApplicationTraceLevel;
83 
84 static bool sEGLSystraceEnabled;
85 static bool sEGLGetErrorEnabled;
86 
87 int gEGLDebugLevel;
88 static int sEGLApplicationDebugLevel;
89 
90 extern gl_hooks_t gHooksTrace;
91 extern gl_hooks_t gHooksSystrace;
92 extern gl_hooks_t gHooksErrorTrace;
93 
setGlTraceThreadSpecific(gl_hooks_t const * value)94 static inline void setGlTraceThreadSpecific(gl_hooks_t const *value) {
95     pthread_setspecific(gGLTraceKey, value);
96 }
97 
getGLTraceThreadSpecific()98 gl_hooks_t const* getGLTraceThreadSpecific() {
99     return static_cast<gl_hooks_t*>(pthread_getspecific(gGLTraceKey));
100 }
101 
initEglTraceLevel()102 void initEglTraceLevel() {
103     char value[PROPERTY_VALUE_MAX];
104     property_get("debug.egl.trace", value, "0");
105 
106     sEGLGetErrorEnabled = !strcasecmp(value, "error");
107     if (sEGLGetErrorEnabled) {
108         sEGLSystraceEnabled = false;
109         sEGLTraceLevel = 0;
110         return;
111     }
112 
113     sEGLSystraceEnabled = !strcasecmp(value, "systrace");
114     if (sEGLSystraceEnabled) {
115         sEGLTraceLevel = 0;
116         return;
117     }
118 
119     int propertyLevel = atoi(value);
120     int applicationLevel = sEGLApplicationTraceLevel;
121     sEGLTraceLevel = propertyLevel > applicationLevel ? propertyLevel : applicationLevel;
122 }
123 
initEglDebugLevel()124 void initEglDebugLevel() {
125     int propertyLevel = 0;
126     char value[PROPERTY_VALUE_MAX];
127 
128     // check system property only on userdebug or eng builds
129     property_get("ro.debuggable", value, "0");
130     if (value[0] == '0')
131         return;
132 
133     property_get("debug.egl.debug_proc", value, "");
134     if (strlen(value) > 0) {
135         long pid = getpid();
136         char procPath[128] = {};
137         sprintf(procPath, "/proc/%ld/cmdline", pid);
138         FILE * file = fopen(procPath, "r");
139         if (file) {
140             char cmdline[256] = {};
141             if (fgets(cmdline, sizeof(cmdline) - 1, file)) {
142                 if (!strncmp(value, cmdline, strlen(value))) {
143                     // set EGL debug if the "debug.egl.debug_proc" property
144                     // matches the prefix of this application's command line
145                     propertyLevel = 1;
146                 }
147             }
148             fclose(file);
149         }
150     }
151 
152     gEGLDebugLevel = propertyLevel || sEGLApplicationDebugLevel;
153     if (gEGLDebugLevel > 0) {
154         GLTrace_start();
155     }
156 }
157 
setGLHooksThreadSpecific(gl_hooks_t const * value)158 void setGLHooksThreadSpecific(gl_hooks_t const *value) {
159     if (sEGLGetErrorEnabled) {
160         setGlTraceThreadSpecific(value);
161         setGlThreadSpecific(&gHooksErrorTrace);
162     } else if (sEGLSystraceEnabled) {
163         setGlTraceThreadSpecific(value);
164         setGlThreadSpecific(&gHooksSystrace);
165     } else if (sEGLTraceLevel > 0) {
166         setGlTraceThreadSpecific(value);
167         setGlThreadSpecific(&gHooksTrace);
168     } else if (gEGLDebugLevel > 0 && value != &gHooksNoContext) {
169         setGlTraceThreadSpecific(value);
170         setGlThreadSpecific(GLTrace_getGLHooks());
171     } else {
172         setGlThreadSpecific(value);
173     }
174 }
175 
176 /*
177  * Global entry point to allow applications to modify their own trace level.
178  * The effective trace level is the max of this level and the value of debug.egl.trace.
179  */
180 extern "C"
setGLTraceLevel(int level)181 void setGLTraceLevel(int level) {
182     sEGLApplicationTraceLevel = level;
183 }
184 
185 /*
186  * Global entry point to allow applications to modify their own debug level.
187  * Debugging is enabled if either the application requested it, or if the system property
188  * matches the application's name.
189  */
setGLDebugLevel(int level)190 void EGLAPI setGLDebugLevel(int level) {
191     sEGLApplicationDebugLevel = level;
192 }
193 
194 #else
195 
setGLHooksThreadSpecific(gl_hooks_t const * value)196 void setGLHooksThreadSpecific(gl_hooks_t const *value) {
197     setGlThreadSpecific(value);
198 }
199 
200 #endif
201 
202 /*****************************************************************************/
203 
gl_no_context()204 static int gl_no_context() {
205     if (egl_tls_t::logNoContextCall()) {
206         char const* const error = "call to OpenGL ES API with "
207                 "no current context (logged once per thread)";
208         if (LOG_NDEBUG) {
209             ALOGE(error);
210         } else {
211             LOG_ALWAYS_FATAL(error);
212         }
213         char value[PROPERTY_VALUE_MAX];
214         property_get("debug.egl.callstack", value, "0");
215         if (atoi(value)) {
216             CallStack stack;
217             stack.update();
218             stack.dump();
219         }
220     }
221     return 0;
222 }
223 
early_egl_init(void)224 static void early_egl_init(void)
225 {
226 #if !USE_FAST_TLS_KEY
227     pthread_key_create(&gGLWrapperKey, NULL);
228 #endif
229 #if EGL_TRACE
230     pthread_key_create(&gGLTraceKey, NULL);
231     initEglTraceLevel();
232     initEglDebugLevel();
233 #endif
234     uint32_t addr = (uint32_t)((void*)gl_no_context);
235     android_memset32(
236             (uint32_t*)(void*)&gHooksNoContext,
237             addr,
238             sizeof(gHooksNoContext));
239 
240     setGLHooksThreadSpecific(&gHooksNoContext);
241 }
242 
243 static pthread_once_t once_control = PTHREAD_ONCE_INIT;
244 static int sEarlyInitState = pthread_once(&once_control, &early_egl_init);
245 
246 // ----------------------------------------------------------------------------
247 
validate_display(EGLDisplay dpy)248 egl_display_ptr validate_display(EGLDisplay dpy) {
249     egl_display_ptr dp = get_display(dpy);
250     if (!dp)
251         return setError(EGL_BAD_DISPLAY, egl_display_ptr(NULL));
252     if (!dp->isReady())
253         return setError(EGL_NOT_INITIALIZED, egl_display_ptr(NULL));
254 
255     return dp;
256 }
257 
validate_display_connection(EGLDisplay dpy,egl_connection_t * & cnx)258 egl_display_ptr validate_display_connection(EGLDisplay dpy,
259         egl_connection_t*& cnx) {
260     cnx = NULL;
261     egl_display_ptr dp = validate_display(dpy);
262     if (!dp)
263         return dp;
264     cnx = &gEGLImpl;
265     if (cnx->dso == 0) {
266         return setError(EGL_BAD_CONFIG, egl_display_ptr(NULL));
267     }
268     return dp;
269 }
270 
271 // ----------------------------------------------------------------------------
272 
egl_get_string_for_current_context(GLenum name)273 const GLubyte * egl_get_string_for_current_context(GLenum name) {
274     // NOTE: returning NULL here will fall-back to the default
275     // implementation.
276 
277     EGLContext context = egl_tls_t::getContext();
278     if (context == EGL_NO_CONTEXT)
279         return NULL;
280 
281     egl_context_t const * const c = get_context(context);
282     if (c == NULL) // this should never happen, by construction
283         return NULL;
284 
285     if (name != GL_EXTENSIONS)
286         return NULL;
287 
288     return (const GLubyte *)c->gl_extensions.string();
289 }
290 
291 // ----------------------------------------------------------------------------
292 
293 // this mutex protects:
294 //    d->disp[]
295 //    egl_init_drivers_locked()
296 //
egl_init_drivers_locked()297 static EGLBoolean egl_init_drivers_locked() {
298     if (sEarlyInitState) {
299         // initialized by static ctor. should be set here.
300         return EGL_FALSE;
301     }
302 
303     // get our driver loader
304     Loader& loader(Loader::getInstance());
305 
306     // dynamically load our EGL implementation
307     egl_connection_t* cnx = &gEGLImpl;
308     if (cnx->dso == 0) {
309         cnx->hooks[egl_connection_t::GLESv1_INDEX] =
310                 &gHooks[egl_connection_t::GLESv1_INDEX];
311         cnx->hooks[egl_connection_t::GLESv2_INDEX] =
312                 &gHooks[egl_connection_t::GLESv2_INDEX];
313         cnx->dso = loader.open(cnx);
314     }
315 
316     return cnx->dso ? EGL_TRUE : EGL_FALSE;
317 }
318 
319 static pthread_mutex_t sInitDriverMutex = PTHREAD_MUTEX_INITIALIZER;
320 
egl_init_drivers()321 EGLBoolean egl_init_drivers() {
322     EGLBoolean res;
323     pthread_mutex_lock(&sInitDriverMutex);
324     res = egl_init_drivers_locked();
325     pthread_mutex_unlock(&sInitDriverMutex);
326     return res;
327 }
328 
gl_unimplemented()329 void gl_unimplemented() {
330     ALOGE("called unimplemented OpenGL ES API");
331 }
332 
gl_noop()333 void gl_noop() {
334 }
335 
336 // ----------------------------------------------------------------------------
337 
338 #if USE_FAST_TLS_KEY
339 
340 // We have a dedicated TLS slot in bionic
get_tls_hooks()341 static inline gl_hooks_t const * volatile * get_tls_hooks() {
342     volatile void *tls_base = __get_tls();
343     gl_hooks_t const * volatile * tls_hooks =
344             reinterpret_cast<gl_hooks_t const * volatile *>(tls_base);
345     return tls_hooks;
346 }
347 
setGlThreadSpecific(gl_hooks_t const * value)348 void setGlThreadSpecific(gl_hooks_t const *value) {
349     gl_hooks_t const * volatile * tls_hooks = get_tls_hooks();
350     tls_hooks[TLS_SLOT_OPENGL_API] = value;
351 }
352 
getGlThreadSpecific()353 gl_hooks_t const* getGlThreadSpecific() {
354     gl_hooks_t const * volatile * tls_hooks = get_tls_hooks();
355     gl_hooks_t const* hooks = tls_hooks[TLS_SLOT_OPENGL_API];
356     if (hooks) return hooks;
357     return &gHooksNoContext;
358 }
359 
360 #else
361 
setGlThreadSpecific(gl_hooks_t const * value)362 void setGlThreadSpecific(gl_hooks_t const *value) {
363     pthread_setspecific(gGLWrapperKey, value);
364 }
365 
getGlThreadSpecific()366 gl_hooks_t const* getGlThreadSpecific() {
367     gl_hooks_t const* hooks =  static_cast<gl_hooks_t*>(pthread_getspecific(gGLWrapperKey));
368     if (hooks) return hooks;
369     return &gHooksNoContext;
370 }
371 
372 #endif
373 
374 // ----------------------------------------------------------------------------
375 // GL / EGL hooks
376 // ----------------------------------------------------------------------------
377 
378 #undef GL_ENTRY
379 #undef EGL_ENTRY
380 #define GL_ENTRY(_r, _api, ...) #_api,
381 #define EGL_ENTRY(_r, _api, ...) #_api,
382 
383 char const * const gl_names[] = {
384     #include "entries.in"
385     NULL
386 };
387 
388 char const * const egl_names[] = {
389     #include "egl_entries.in"
390     NULL
391 };
392 
393 #undef GL_ENTRY
394 #undef EGL_ENTRY
395 
396 
397 // ----------------------------------------------------------------------------
398 }; // namespace android
399 // ----------------------------------------------------------------------------
400 
401