egl_display.cpp revision cc2b1560e87369676a2d13f17bd1ff4021a91819
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        return setError(EGL_NOT_INITIALIZED, EGL_FALSE);
267    }
268
269    // this is specific to Android, display termination is ref-counted.
270    if (refs > 1) {
271        refs--;
272        return EGL_TRUE;
273    }
274
275    EGLBoolean res = EGL_FALSE;
276    egl_connection_t* const cnx = &gEGLImpl;
277    if (cnx->dso && disp.state == egl_display_t::INITIALIZED) {
278        if (cnx->egl.eglTerminate(disp.dpy) == EGL_FALSE) {
279            ALOGW("eglTerminate(%p) failed (%s)", disp.dpy,
280                    egl_tls_t::egl_strerror(cnx->egl.eglGetError()));
281        }
282        // REVISIT: it's unclear what to do if eglTerminate() fails
283        disp.state = egl_display_t::TERMINATED;
284        res = EGL_TRUE;
285    }
286
287    mHibernation.setDisplayValid(false);
288
289    // Mark all objects remaining in the list as terminated, unless
290    // there are no reference to them, it which case, we're free to
291    // delete them.
292    size_t count = objects.size();
293    ALOGW_IF(count, "eglTerminate() called w/ %d objects remaining", count);
294    for (size_t i=0 ; i<count ; i++) {
295        egl_object_t* o = objects.itemAt(i);
296        o->destroy();
297    }
298
299    // this marks all object handles are "terminated"
300    objects.clear();
301
302    refs--;
303    return res;
304}
305
306void egl_display_t::loseCurrent(egl_context_t * cur_c)
307{
308    if (cur_c) {
309        egl_display_t* display = cur_c->getDisplay();
310        if (display) {
311            display->loseCurrentImpl(cur_c);
312        }
313    }
314}
315
316void egl_display_t::loseCurrentImpl(egl_context_t * cur_c)
317{
318    // by construction, these are either 0 or valid (possibly terminated)
319    // it should be impossible for these to be invalid
320    ContextRef _cur_c(cur_c);
321    SurfaceRef _cur_r(cur_c ? get_surface(cur_c->read) : NULL);
322    SurfaceRef _cur_d(cur_c ? get_surface(cur_c->draw) : NULL);
323
324    { // scope for the lock
325        Mutex::Autolock _l(lock);
326        cur_c->onLooseCurrent();
327
328    }
329
330    // This cannot be called with the lock held because it might end-up
331    // calling back into EGL (in particular when a surface is destroyed
332    // it calls ANativeWindow::disconnect
333    _cur_c.release();
334    _cur_r.release();
335    _cur_d.release();
336}
337
338EGLBoolean egl_display_t::makeCurrent(egl_context_t* c, egl_context_t* cur_c,
339        EGLSurface draw, EGLSurface read, EGLContext ctx,
340        EGLSurface impl_draw, EGLSurface impl_read, EGLContext impl_ctx)
341{
342    EGLBoolean result;
343
344    // by construction, these are either 0 or valid (possibly terminated)
345    // it should be impossible for these to be invalid
346    ContextRef _cur_c(cur_c);
347    SurfaceRef _cur_r(cur_c ? get_surface(cur_c->read) : NULL);
348    SurfaceRef _cur_d(cur_c ? get_surface(cur_c->draw) : NULL);
349
350    { // scope for the lock
351        Mutex::Autolock _l(lock);
352        if (c) {
353            result = c->cnx->egl.eglMakeCurrent(
354                    disp.dpy, impl_draw, impl_read, impl_ctx);
355            if (result == EGL_TRUE) {
356                c->onMakeCurrent(draw, read);
357                if (!cur_c) {
358                    mHibernation.incWakeCount(HibernationMachine::STRONG);
359                }
360            }
361        } else {
362            result = cur_c->cnx->egl.eglMakeCurrent(
363                    disp.dpy, impl_draw, impl_read, impl_ctx);
364            if (result == EGL_TRUE) {
365                cur_c->onLooseCurrent();
366                mHibernation.decWakeCount(HibernationMachine::STRONG);
367            }
368        }
369    }
370
371    if (result == EGL_TRUE) {
372        // This cannot be called with the lock held because it might end-up
373        // calling back into EGL (in particular when a surface is destroyed
374        // it calls ANativeWindow::disconnect
375        _cur_c.release();
376        _cur_r.release();
377        _cur_d.release();
378    }
379
380    return result;
381}
382
383// ----------------------------------------------------------------------------
384
385bool egl_display_t::HibernationMachine::incWakeCount(WakeRefStrength strength) {
386    Mutex::Autolock _l(mLock);
387    ALOGE_IF(mWakeCount < 0 || mWakeCount == INT32_MAX,
388             "Invalid WakeCount (%d) on enter\n", mWakeCount);
389
390    mWakeCount++;
391    if (strength == STRONG)
392        mAttemptHibernation = false;
393
394    if (CC_UNLIKELY(mHibernating)) {
395        ALOGV("Awakening\n");
396        egl_connection_t* const cnx = &gEGLImpl;
397
398        // These conditions should be guaranteed before entering hibernation;
399        // we don't want to get into a state where we can't wake up.
400        ALOGD_IF(!mDpyValid || !cnx->egl.eglAwakenProcessIMG,
401                 "Invalid hibernation state, unable to awaken\n");
402
403        if (!cnx->egl.eglAwakenProcessIMG()) {
404            ALOGE("Failed to awaken EGL implementation\n");
405            return false;
406        }
407        mHibernating = false;
408    }
409    return true;
410}
411
412void egl_display_t::HibernationMachine::decWakeCount(WakeRefStrength strength) {
413    Mutex::Autolock _l(mLock);
414    ALOGE_IF(mWakeCount <= 0, "Invalid WakeCount (%d) on leave\n", mWakeCount);
415
416    mWakeCount--;
417    if (strength == STRONG)
418        mAttemptHibernation = true;
419
420    if (mWakeCount == 0 && CC_UNLIKELY(mAttemptHibernation)) {
421        egl_connection_t* const cnx = &gEGLImpl;
422        mAttemptHibernation = false;
423        if (mAllowHibernation && mDpyValid &&
424                cnx->egl.eglHibernateProcessIMG &&
425                cnx->egl.eglAwakenProcessIMG) {
426            ALOGV("Hibernating\n");
427            if (!cnx->egl.eglHibernateProcessIMG()) {
428                ALOGE("Failed to hibernate EGL implementation\n");
429                return;
430            }
431            mHibernating = true;
432        }
433    }
434}
435
436void egl_display_t::HibernationMachine::setDisplayValid(bool valid) {
437    Mutex::Autolock _l(mLock);
438    mDpyValid = valid;
439}
440
441// ----------------------------------------------------------------------------
442}; // namespace android
443// ----------------------------------------------------------------------------
444