egl.cpp revision e03de9379410fd9947189f0f14e3ec457df2ebfe
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 "glesv2dbg.h"
41#include "hooks.h"
42#include "Loader.h"
43
44#include "egl_display.h"
45#include "egl_object.h"
46
47// ----------------------------------------------------------------------------
48namespace android {
49// ----------------------------------------------------------------------------
50
51egl_connection_t gEGLImpl[IMPL_NUM_IMPLEMENTATIONS];
52gl_hooks_t gHooks[2][IMPL_NUM_IMPLEMENTATIONS];
53gl_hooks_t gHooksNoContext;
54pthread_key_t gGLWrapperKey = -1;
55
56// ----------------------------------------------------------------------------
57
58#if EGL_TRACE
59
60EGLAPI pthread_key_t gGLTraceKey = -1;
61
62// ----------------------------------------------------------------------------
63
64int gEGLDebugLevel;
65
66static int sEGLTraceLevel;
67static int sEGLApplicationTraceLevel;
68
69extern gl_hooks_t gHooksTrace;
70extern gl_hooks_t gHooksDebug;
71
72static inline void setGlTraceThreadSpecific(gl_hooks_t const *value) {
73    pthread_setspecific(gGLTraceKey, value);
74}
75
76gl_hooks_t const* getGLTraceThreadSpecific() {
77    return static_cast<gl_hooks_t*>(pthread_getspecific(gGLTraceKey));
78}
79
80void initEglTraceLevel() {
81    char value[PROPERTY_VALUE_MAX];
82    property_get("debug.egl.trace", value, "0");
83    int propertyLevel = atoi(value);
84    int applicationLevel = sEGLApplicationTraceLevel;
85    sEGLTraceLevel = propertyLevel > applicationLevel ? propertyLevel : applicationLevel;
86
87    property_get("debug.egl.debug_proc", value, "");
88    long pid = getpid();
89    char procPath[128] = {};
90    sprintf(procPath, "/proc/%ld/cmdline", pid);
91    FILE * file = fopen(procPath, "r");
92    if (file)
93    {
94        char cmdline[256] = {};
95        if (fgets(cmdline, sizeof(cmdline) - 1, file))
96        {
97            if (!strcmp(value, cmdline))
98                sEGLTraceLevel = 1;
99        }
100        fclose(file);
101    }
102
103    if (sEGLTraceLevel > 0)
104    {
105        property_get("debug.egl.debug_port", value, "5039");
106        const unsigned short port = (unsigned short)atoi(value);
107        property_get("debug.egl.debug_forceUseFile", value, "0");
108        const bool forceUseFile = (bool)atoi(value);
109        property_get("debug.egl.debug_maxFileSize", value, "8");
110        const unsigned int maxFileSize = atoi(value) << 20;
111        property_get("debug.egl.debug_filePath", value, "/data/local/tmp/dump.gles2dbg");
112        StartDebugServer(port, forceUseFile, maxFileSize, value);
113    }
114}
115
116void setGLHooksThreadSpecific(gl_hooks_t const *value) {
117    if (sEGLTraceLevel > 0) {
118        setGlTraceThreadSpecific(value);
119        setGlThreadSpecific(&gHooksTrace);
120    } else if (sEGLTraceLevel > 0 && value != &gHooksNoContext) {
121        setGlTraceThreadSpecific(value);
122        setGlThreadSpecific(&gHooksDebug);
123    } else {
124        setGlThreadSpecific(value);
125    }
126}
127
128/*
129 * Global entry point to allow applications to modify their own trace level.
130 * The effective trace level is the max of this level and the value of debug.egl.trace.
131 */
132extern "C"
133void setGLTraceLevel(int level) {
134    sEGLApplicationTraceLevel = level;
135}
136
137#else
138
139void setGLHooksThreadSpecific(gl_hooks_t const *value) {
140    setGlThreadSpecific(value);
141}
142
143#endif
144
145/*****************************************************************************/
146
147static int gl_no_context() {
148    if (egl_tls_t::logNoContextCall()) {
149        LOGE("call to OpenGL ES API with no current context "
150             "(logged once per thread)");
151        LOGE("call stack before error:");
152        CallStack stack;
153        stack.update();
154        stack.dump();
155    }
156    return 0;
157}
158
159static void early_egl_init(void)
160{
161#if !USE_FAST_TLS_KEY
162    pthread_key_create(&gGLWrapperKey, NULL);
163#endif
164#if EGL_TRACE
165    pthread_key_create(&gGLTraceKey, NULL);
166    initEglTraceLevel();
167#endif
168    uint32_t addr = (uint32_t)((void*)gl_no_context);
169    android_memset32(
170            (uint32_t*)(void*)&gHooksNoContext,
171            addr,
172            sizeof(gHooksNoContext));
173
174    setGLHooksThreadSpecific(&gHooksNoContext);
175}
176
177static pthread_once_t once_control = PTHREAD_ONCE_INIT;
178static int sEarlyInitState = pthread_once(&once_control, &early_egl_init);
179
180// ----------------------------------------------------------------------------
181
182egl_display_t* validate_display(EGLDisplay dpy) {
183    egl_display_t * const dp = get_display(dpy);
184    if (!dp)
185        return setError(EGL_BAD_DISPLAY, (egl_display_t*)NULL);
186    if (!dp->isReady())
187        return setError(EGL_NOT_INITIALIZED, (egl_display_t*)NULL);
188
189    return dp;
190}
191
192egl_connection_t* validate_display_config(EGLDisplay dpy, EGLConfig config,
193        egl_display_t const*& dp) {
194    dp = validate_display(dpy);
195    if (!dp)
196        return (egl_connection_t*) NULL;
197
198    if (intptr_t(config) >= dp->numTotalConfigs) {
199        return setError(EGL_BAD_CONFIG, (egl_connection_t*)NULL);
200    }
201    egl_connection_t* const cnx = &gEGLImpl[dp->configs[intptr_t(config)].impl];
202    if (cnx->dso == 0) {
203        return setError(EGL_BAD_CONFIG, (egl_connection_t*)NULL);
204    }
205    return cnx;
206}
207
208// ----------------------------------------------------------------------------
209
210EGLImageKHR egl_get_image_for_current_context(EGLImageKHR image)
211{
212    ImageRef _i(image);
213    if (!_i.get())
214        return EGL_NO_IMAGE_KHR;
215
216    EGLContext context = egl_tls_t::getContext();
217    if (context == EGL_NO_CONTEXT || image == EGL_NO_IMAGE_KHR)
218        return EGL_NO_IMAGE_KHR;
219
220    egl_context_t const * const c = get_context(context);
221    if (c == NULL) // this should never happen
222        return EGL_NO_IMAGE_KHR;
223
224    // here we don't validate the context because if it's been marked for
225    // termination, this call should still succeed since it's internal to
226    // EGL.
227
228    egl_image_t const * const i = get_image(image);
229    return i->images[c->impl];
230}
231
232// ----------------------------------------------------------------------------
233
234// this mutex protects:
235//    d->disp[]
236//    egl_init_drivers_locked()
237//
238static EGLBoolean egl_init_drivers_locked() {
239    if (sEarlyInitState) {
240        // initialized by static ctor. should be set here.
241        return EGL_FALSE;
242    }
243
244    // get our driver loader
245    Loader& loader(Loader::getInstance());
246
247    // dynamically load all our EGL implementations
248    egl_connection_t* cnx;
249
250    cnx = &gEGLImpl[IMPL_SOFTWARE];
251    if (cnx->dso == 0) {
252        cnx->hooks[GLESv1_INDEX] = &gHooks[GLESv1_INDEX][IMPL_SOFTWARE];
253        cnx->hooks[GLESv2_INDEX] = &gHooks[GLESv2_INDEX][IMPL_SOFTWARE];
254        cnx->dso = loader.open(EGL_DEFAULT_DISPLAY, 0, cnx);
255    }
256
257    cnx = &gEGLImpl[IMPL_HARDWARE];
258    if (cnx->dso == 0) {
259        char value[PROPERTY_VALUE_MAX];
260        property_get("debug.egl.hw", value, "1");
261        if (atoi(value) != 0) {
262            cnx->hooks[GLESv1_INDEX] = &gHooks[GLESv1_INDEX][IMPL_HARDWARE];
263            cnx->hooks[GLESv2_INDEX] = &gHooks[GLESv2_INDEX][IMPL_HARDWARE];
264            cnx->dso = loader.open(EGL_DEFAULT_DISPLAY, 1, cnx);
265        } else {
266            LOGD("3D hardware acceleration is disabled");
267        }
268    }
269
270    if (!gEGLImpl[IMPL_SOFTWARE].dso && !gEGLImpl[IMPL_HARDWARE].dso) {
271        return EGL_FALSE;
272    }
273
274    return EGL_TRUE;
275}
276
277static pthread_mutex_t sInitDriverMutex = PTHREAD_MUTEX_INITIALIZER;
278
279EGLBoolean egl_init_drivers() {
280    EGLBoolean res;
281    pthread_mutex_lock(&sInitDriverMutex);
282    res = egl_init_drivers_locked();
283    pthread_mutex_unlock(&sInitDriverMutex);
284    return res;
285}
286
287void gl_unimplemented() {
288    LOGE("called unimplemented OpenGL ES API");
289}
290
291// ----------------------------------------------------------------------------
292
293#if USE_FAST_TLS_KEY
294
295// We have a dedicated TLS slot in bionic
296static inline gl_hooks_t const * volatile * get_tls_hooks() {
297    volatile void *tls_base = __get_tls();
298    gl_hooks_t const * volatile * tls_hooks =
299            reinterpret_cast<gl_hooks_t const * volatile *>(tls_base);
300    return tls_hooks;
301}
302
303void setGlThreadSpecific(gl_hooks_t const *value) {
304    gl_hooks_t const * volatile * tls_hooks = get_tls_hooks();
305    tls_hooks[TLS_SLOT_OPENGL_API] = value;
306}
307
308gl_hooks_t const* getGlThreadSpecific() {
309    gl_hooks_t const * volatile * tls_hooks = get_tls_hooks();
310    gl_hooks_t const* hooks = tls_hooks[TLS_SLOT_OPENGL_API];
311    if (hooks) return hooks;
312    return &gHooksNoContext;
313}
314
315#else
316
317void setGlThreadSpecific(gl_hooks_t const *value) {
318    pthread_setspecific(gGLWrapperKey, value);
319}
320
321gl_hooks_t const* getGlThreadSpecific() {
322    gl_hooks_t const* hooks =  static_cast<gl_hooks_t*>(pthread_getspecific(gGLWrapperKey));
323    if (hooks) return hooks;
324    return &gHooksNoContext;
325}
326
327#endif
328
329// ----------------------------------------------------------------------------
330// GL / EGL hooks
331// ----------------------------------------------------------------------------
332
333#undef GL_ENTRY
334#undef EGL_ENTRY
335#define GL_ENTRY(_r, _api, ...) #_api,
336#define EGL_ENTRY(_r, _api, ...) #_api,
337
338char const * const gl_names[] = {
339    #include "entries.in"
340    NULL
341};
342
343char const * const egl_names[] = {
344    #include "egl_entries.in"
345    NULL
346};
347
348#undef GL_ENTRY
349#undef EGL_ENTRY
350
351
352// ----------------------------------------------------------------------------
353}; // namespace android
354// ----------------------------------------------------------------------------
355
356