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