egl_display.cpp revision 766010858ea7696d64f1b559413670bdd8627595
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 "egl_cache.h"
18#include "egl_display.h"
19#include "egl_object.h"
20#include "egl_tls.h"
21#include "egl_impl.h"
22#include "Loader.h"
23
24// ----------------------------------------------------------------------------
25namespace android {
26// ----------------------------------------------------------------------------
27
28extern void initEglTraceLevel();
29extern void setGLHooksThreadSpecific(gl_hooks_t const *value);
30
31static int cmp_configs(const void* a, const void *b) {
32    const egl_config_t& c0 = *(egl_config_t const *)a;
33    const egl_config_t& c1 = *(egl_config_t const *)b;
34    return c0<c1 ? -1 : (c1<c0 ? 1 : 0);
35}
36
37// ----------------------------------------------------------------------------
38
39egl_display_t egl_display_t::sDisplay[NUM_DISPLAYS];
40
41egl_display_t::egl_display_t() :
42    magic('_dpy'), numTotalConfigs(0), configs(0), refs(0) {
43}
44
45egl_display_t::~egl_display_t() {
46    magic = 0;
47    egl_cache_t::get()->terminate();
48}
49
50egl_display_t* egl_display_t::get(EGLDisplay dpy) {
51    uintptr_t index = uintptr_t(dpy)-1U;
52    return (index >= NUM_DISPLAYS) ? NULL : &sDisplay[index];
53}
54
55void egl_display_t::addObject(egl_object_t* object) {
56    Mutex::Autolock _l(lock);
57    objects.add(object);
58}
59
60void egl_display_t::removeObject(egl_object_t* object) {
61    Mutex::Autolock _l(lock);
62    objects.remove(object);
63}
64
65bool egl_display_t::getObject(egl_object_t* object) {
66    Mutex::Autolock _l(lock);
67    if (objects.indexOf(object) >= 0) {
68        object->incRef();
69        return true;
70    }
71    return false;
72}
73
74EGLDisplay egl_display_t::getFromNativeDisplay(EGLNativeDisplayType disp) {
75    if (uintptr_t(disp) >= NUM_DISPLAYS)
76        return NULL;
77
78    return sDisplay[uintptr_t(disp)].getDisplay(disp);
79}
80
81EGLDisplay egl_display_t::getDisplay(EGLNativeDisplayType display) {
82
83    Mutex::Autolock _l(lock);
84
85    // get our driver loader
86    Loader& loader(Loader::getInstance());
87
88    for (int i = 0; i < IMPL_NUM_IMPLEMENTATIONS; i++) {
89        egl_connection_t* const cnx = &gEGLImpl[i];
90        if (cnx->dso && disp[i].dpy == EGL_NO_DISPLAY) {
91            EGLDisplay dpy = cnx->egl.eglGetDisplay(display);
92            disp[i].dpy = dpy;
93            if (dpy == EGL_NO_DISPLAY) {
94                loader.close(cnx->dso);
95                cnx->dso = NULL;
96            }
97        }
98    }
99
100    return EGLDisplay(uintptr_t(display) + 1U);
101}
102
103EGLBoolean egl_display_t::initialize(EGLint *major, EGLint *minor) {
104
105    Mutex::Autolock _l(lock);
106
107    if (refs > 0) {
108        if (major != NULL)
109            *major = VERSION_MAJOR;
110        if (minor != NULL)
111            *minor = VERSION_MINOR;
112        refs++;
113        return EGL_TRUE;
114    }
115
116#if EGL_TRACE
117
118    // Called both at early_init time and at this time. (Early_init is pre-zygote, so
119    // the information from that call may be stale.)
120    initEglTraceLevel();
121
122#endif
123
124    setGLHooksThreadSpecific(&gHooksNoContext);
125
126    // initialize each EGL and
127    // build our own extension string first, based on the extension we know
128    // and the extension supported by our client implementation
129    for (int i = 0; i < IMPL_NUM_IMPLEMENTATIONS; i++) {
130        egl_connection_t* const cnx = &gEGLImpl[i];
131        cnx->major = -1;
132        cnx->minor = -1;
133        if (!cnx->dso)
134            continue;
135
136#if defined(ADRENO130)
137#warning "Adreno-130 eglInitialize() workaround"
138        /*
139         * The ADRENO 130 driver returns a different EGLDisplay each time
140         * eglGetDisplay() is called, but also makes the EGLDisplay invalid
141         * after eglTerminate() has been called, so that eglInitialize()
142         * cannot be called again. Therefore, we need to make sure to call
143         * eglGetDisplay() before calling eglInitialize();
144         */
145        if (i == IMPL_HARDWARE) {
146            disp[i].dpy =
147            cnx->egl.eglGetDisplay(EGL_DEFAULT_DISPLAY);
148        }
149#endif
150
151        EGLDisplay idpy = disp[i].dpy;
152        if (cnx->egl.eglInitialize(idpy, &cnx->major, &cnx->minor)) {
153            //LOGD("initialized %d dpy=%p, ver=%d.%d, cnx=%p",
154            //        i, idpy, cnx->major, cnx->minor, cnx);
155
156            // display is now initialized
157            disp[i].state = egl_display_t::INITIALIZED;
158
159            // get the query-strings for this display for each implementation
160            disp[i].queryString.vendor = cnx->egl.eglQueryString(idpy,
161                    EGL_VENDOR);
162            disp[i].queryString.version = cnx->egl.eglQueryString(idpy,
163                    EGL_VERSION);
164            disp[i].queryString.extensions = cnx->egl.eglQueryString(idpy,
165                    EGL_EXTENSIONS);
166            disp[i].queryString.clientApi = cnx->egl.eglQueryString(idpy,
167                    EGL_CLIENT_APIS);
168
169        } else {
170            LOGW("%d: eglInitialize(%p) failed (%s)", i, idpy,
171                    egl_tls_t::egl_strerror(cnx->egl.eglGetError()));
172        }
173    }
174
175    egl_cache_t::get()->initialize(this);
176
177    EGLBoolean res = EGL_FALSE;
178    for (int i = 0; i < IMPL_NUM_IMPLEMENTATIONS; i++) {
179        egl_connection_t* const cnx = &gEGLImpl[i];
180        if (cnx->dso && cnx->major >= 0 && cnx->minor >= 0) {
181            EGLint n;
182            if (cnx->egl.eglGetConfigs(disp[i].dpy, 0, 0, &n)) {
183                disp[i].config = (EGLConfig*) malloc(sizeof(EGLConfig) * n);
184                if (disp[i].config) {
185                    if (cnx->egl.eglGetConfigs(disp[i].dpy, disp[i].config, n,
186                            &disp[i].numConfigs)) {
187                        numTotalConfigs += n;
188                        res = EGL_TRUE;
189                    }
190                }
191            }
192        }
193    }
194
195    if (res == EGL_TRUE) {
196        configs = new egl_config_t[numTotalConfigs];
197        for (int i = 0, k = 0; i < IMPL_NUM_IMPLEMENTATIONS; i++) {
198            egl_connection_t* const cnx = &gEGLImpl[i];
199            if (cnx->dso && cnx->major >= 0 && cnx->minor >= 0) {
200                for (int j = 0; j < disp[i].numConfigs; j++) {
201                    configs[k].impl = i;
202                    configs[k].config = disp[i].config[j];
203                    configs[k].configId = k + 1; // CONFIG_ID start at 1
204                    // store the implementation's CONFIG_ID
205                    cnx->egl.eglGetConfigAttrib(disp[i].dpy, disp[i].config[j],
206                            EGL_CONFIG_ID, &configs[k].implConfigId);
207                    k++;
208                }
209            }
210        }
211
212        // sort our configurations so we can do binary-searches
213        qsort(configs, numTotalConfigs, sizeof(egl_config_t), cmp_configs);
214
215        refs++;
216        if (major != NULL)
217            *major = VERSION_MAJOR;
218        if (minor != NULL)
219            *minor = VERSION_MINOR;
220        return EGL_TRUE;
221    }
222    return setError(EGL_NOT_INITIALIZED, EGL_FALSE);
223}
224
225EGLBoolean egl_display_t::terminate() {
226
227    Mutex::Autolock _l(lock);
228
229    if (refs == 0) {
230        return setError(EGL_NOT_INITIALIZED, EGL_FALSE);
231    }
232
233    // this is specific to Android, display termination is ref-counted.
234    if (refs > 1) {
235        refs--;
236        return EGL_TRUE;
237    }
238
239    EGLBoolean res = EGL_FALSE;
240    for (int i = 0; i < IMPL_NUM_IMPLEMENTATIONS; i++) {
241        egl_connection_t* const cnx = &gEGLImpl[i];
242        if (cnx->dso && disp[i].state == egl_display_t::INITIALIZED) {
243            if (cnx->egl.eglTerminate(disp[i].dpy) == EGL_FALSE) {
244                LOGW("%d: eglTerminate(%p) failed (%s)", i, disp[i].dpy,
245                        egl_tls_t::egl_strerror(cnx->egl.eglGetError()));
246            }
247            // REVISIT: it's unclear what to do if eglTerminate() fails
248            free(disp[i].config);
249
250            disp[i].numConfigs = 0;
251            disp[i].config = 0;
252            disp[i].state = egl_display_t::TERMINATED;
253
254            res = EGL_TRUE;
255        }
256    }
257
258    // Mark all objects remaining in the list as terminated, unless
259    // there are no reference to them, it which case, we're free to
260    // delete them.
261    size_t count = objects.size();
262    LOGW_IF(count, "eglTerminate() called w/ %d objects remaining", count);
263    for (size_t i=0 ; i<count ; i++) {
264        egl_object_t* o = objects.itemAt(i);
265        o->destroy();
266    }
267
268    // this marks all object handles are "terminated"
269    objects.clear();
270
271    refs--;
272    numTotalConfigs = 0;
273    delete[] configs;
274    return res;
275}
276
277
278// ----------------------------------------------------------------------------
279}; // namespace android
280// ----------------------------------------------------------------------------
281