egl_display.cpp revision 4b9511c16195a646242eff833b0af212933b6eca
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 <string.h>
18
19#include "egl_cache.h"
20#include "egl_display.h"
21#include "egl_object.h"
22#include "egl_tls.h"
23#include "egl_impl.h"
24#include "Loader.h"
25
26// ----------------------------------------------------------------------------
27namespace android {
28// ----------------------------------------------------------------------------
29
30static char const * const sVendorString     = "Android";
31static char const * const sVersionString    = "1.4 Android META-EGL";
32static char const * const sClientApiString  = "OpenGL ES";
33
34// this is the list of EGL extensions that are exposed to applications
35// some of them are mandatory because used by the ANDROID system.
36//
37// mandatory extensions are required per the CDD and not explicitly
38// checked during EGL initialization. the system *assumes* these extensions
39// are present. the system may not function properly if some mandatory
40// extensions are missing.
41//
42// NOTE: sExtensionString MUST be have a single space as the last character.
43//
44static char const * const sExtensionString  =
45        "EGL_KHR_image "                        // mandatory
46        "EGL_KHR_image_base "                   // mandatory
47        "EGL_KHR_image_pixmap "
48        "EGL_KHR_gl_texture_2D_image "
49        "EGL_KHR_gl_texture_cubemap_image "
50        "EGL_KHR_gl_renderbuffer_image "
51        "EGL_KHR_fence_sync "
52        "EGL_NV_system_time "
53        "EGL_ANDROID_image_native_buffer "      // mandatory
54        ;
55
56// extensions not exposed to applications but used by the ANDROID system
57//      "EGL_ANDROID_recordable "               // mandatory
58//      "EGL_ANDROID_blob_cache "               // strongly recommended
59
60extern void initEglTraceLevel();
61extern void setGLHooksThreadSpecific(gl_hooks_t const *value);
62
63static int cmp_configs(const void* a, const void *b) {
64    const egl_config_t& c0 = *(egl_config_t const *)a;
65    const egl_config_t& c1 = *(egl_config_t const *)b;
66    return c0<c1 ? -1 : (c1<c0 ? 1 : 0);
67}
68
69// ----------------------------------------------------------------------------
70
71egl_display_t egl_display_t::sDisplay[NUM_DISPLAYS];
72
73egl_display_t::egl_display_t() :
74    magic('_dpy'), numTotalConfigs(0), configs(0), refs(0) {
75}
76
77egl_display_t::~egl_display_t() {
78    magic = 0;
79    egl_cache_t::get()->terminate();
80}
81
82egl_display_t* egl_display_t::get(EGLDisplay dpy) {
83    uintptr_t index = uintptr_t(dpy)-1U;
84    return (index >= NUM_DISPLAYS) ? NULL : &sDisplay[index];
85}
86
87void egl_display_t::addObject(egl_object_t* object) {
88    Mutex::Autolock _l(lock);
89    objects.add(object);
90}
91
92void egl_display_t::removeObject(egl_object_t* object) {
93    Mutex::Autolock _l(lock);
94    objects.remove(object);
95}
96
97bool egl_display_t::getObject(egl_object_t* object) const {
98    Mutex::Autolock _l(lock);
99    if (objects.indexOf(object) >= 0) {
100        if (object->getDisplay() == this) {
101            object->incRef();
102            return true;
103        }
104    }
105    return false;
106}
107
108EGLDisplay egl_display_t::getFromNativeDisplay(EGLNativeDisplayType disp) {
109    if (uintptr_t(disp) >= NUM_DISPLAYS)
110        return NULL;
111
112    return sDisplay[uintptr_t(disp)].getDisplay(disp);
113}
114
115EGLDisplay egl_display_t::getDisplay(EGLNativeDisplayType display) {
116
117    Mutex::Autolock _l(lock);
118
119    // get our driver loader
120    Loader& loader(Loader::getInstance());
121
122    for (int i = 0; i < IMPL_NUM_IMPLEMENTATIONS; i++) {
123        egl_connection_t* const cnx = &gEGLImpl[i];
124        if (cnx->dso && disp[i].dpy == EGL_NO_DISPLAY) {
125            EGLDisplay dpy = cnx->egl.eglGetDisplay(display);
126            disp[i].dpy = dpy;
127            if (dpy == EGL_NO_DISPLAY) {
128                loader.close(cnx->dso);
129                cnx->dso = NULL;
130            }
131        }
132    }
133
134    return EGLDisplay(uintptr_t(display) + 1U);
135}
136
137EGLBoolean egl_display_t::initialize(EGLint *major, EGLint *minor) {
138
139    Mutex::Autolock _l(lock);
140
141    if (refs > 0) {
142        if (major != NULL)
143            *major = VERSION_MAJOR;
144        if (minor != NULL)
145            *minor = VERSION_MINOR;
146        refs++;
147        return EGL_TRUE;
148    }
149
150#if EGL_TRACE
151
152    // Called both at early_init time and at this time. (Early_init is pre-zygote, so
153    // the information from that call may be stale.)
154    initEglTraceLevel();
155
156#endif
157
158    setGLHooksThreadSpecific(&gHooksNoContext);
159
160    // initialize each EGL and
161    // build our own extension string first, based on the extension we know
162    // and the extension supported by our client implementation
163    for (int i = 0; i < IMPL_NUM_IMPLEMENTATIONS; i++) {
164        egl_connection_t* const cnx = &gEGLImpl[i];
165        cnx->major = -1;
166        cnx->minor = -1;
167        if (!cnx->dso)
168            continue;
169
170#if defined(ADRENO130)
171#warning "Adreno-130 eglInitialize() workaround"
172        /*
173         * The ADRENO 130 driver returns a different EGLDisplay each time
174         * eglGetDisplay() is called, but also makes the EGLDisplay invalid
175         * after eglTerminate() has been called, so that eglInitialize()
176         * cannot be called again. Therefore, we need to make sure to call
177         * eglGetDisplay() before calling eglInitialize();
178         */
179        if (i == IMPL_HARDWARE) {
180            disp[i].dpy =
181            cnx->egl.eglGetDisplay(EGL_DEFAULT_DISPLAY);
182        }
183#endif
184
185        EGLDisplay idpy = disp[i].dpy;
186        if (cnx->egl.eglInitialize(idpy, &cnx->major, &cnx->minor)) {
187            //LOGD("initialized %d dpy=%p, ver=%d.%d, cnx=%p",
188            //        i, idpy, cnx->major, cnx->minor, cnx);
189
190            // display is now initialized
191            disp[i].state = egl_display_t::INITIALIZED;
192
193            // get the query-strings for this display for each implementation
194            disp[i].queryString.vendor = cnx->egl.eglQueryString(idpy,
195                    EGL_VENDOR);
196            disp[i].queryString.version = cnx->egl.eglQueryString(idpy,
197                    EGL_VERSION);
198            disp[i].queryString.extensions = cnx->egl.eglQueryString(idpy,
199                    EGL_EXTENSIONS);
200            disp[i].queryString.clientApi = cnx->egl.eglQueryString(idpy,
201                    EGL_CLIENT_APIS);
202
203        } else {
204            LOGW("%d: eglInitialize(%p) failed (%s)", i, idpy,
205                    egl_tls_t::egl_strerror(cnx->egl.eglGetError()));
206        }
207    }
208
209    // the query strings are per-display
210    mVendorString.setTo(sVendorString);
211    mVersionString.setTo(sVersionString);
212    mClientApiString.setTo(sClientApiString);
213
214    // we only add extensions that exist in at least one implementation
215    char const* start = sExtensionString;
216    char const* end;
217    do {
218        // find the space separating this extension for the next one
219        end = strchr(start, ' ');
220        if (end) {
221            // length of the extension string
222            const size_t len = end - start;
223            // NOTE: we could avoid the copy if we had strnstr.
224            const String8 ext(start, len);
225            // now go through all implementations and look for this extension
226            for (int i = 0; i < IMPL_NUM_IMPLEMENTATIONS; i++) {
227                // if we find it, add this extension string to our list
228                // (and don't forget the space)
229                const char* match = strstr(disp[i].queryString.extensions, ext.string());
230                if (match && (match[len] == ' ' || match[len] == 0)) {
231                    mExtensionString.append(start, len+1);
232                }
233            }
234            // process the next extension string, and skip the space.
235            start = end + 1;
236        }
237    } while (end);
238
239    egl_cache_t::get()->initialize(this);
240
241    EGLBoolean res = EGL_FALSE;
242    for (int i = 0; i < IMPL_NUM_IMPLEMENTATIONS; i++) {
243        egl_connection_t* const cnx = &gEGLImpl[i];
244        if (cnx->dso && cnx->major >= 0 && cnx->minor >= 0) {
245            EGLint n;
246            if (cnx->egl.eglGetConfigs(disp[i].dpy, 0, 0, &n)) {
247                disp[i].config = (EGLConfig*) malloc(sizeof(EGLConfig) * n);
248                if (disp[i].config) {
249                    if (cnx->egl.eglGetConfigs(disp[i].dpy, disp[i].config, n,
250                            &disp[i].numConfigs)) {
251                        numTotalConfigs += n;
252                        res = EGL_TRUE;
253                    }
254                }
255            }
256        }
257    }
258
259    if (res == EGL_TRUE) {
260        configs = new egl_config_t[numTotalConfigs];
261        for (int i = 0, k = 0; i < IMPL_NUM_IMPLEMENTATIONS; i++) {
262            egl_connection_t* const cnx = &gEGLImpl[i];
263            if (cnx->dso && cnx->major >= 0 && cnx->minor >= 0) {
264                for (int j = 0; j < disp[i].numConfigs; j++) {
265                    configs[k].impl = i;
266                    configs[k].config = disp[i].config[j];
267                    configs[k].configId = k + 1; // CONFIG_ID start at 1
268                    // store the implementation's CONFIG_ID
269                    cnx->egl.eglGetConfigAttrib(disp[i].dpy, disp[i].config[j],
270                            EGL_CONFIG_ID, &configs[k].implConfigId);
271                    k++;
272                }
273            }
274        }
275
276        // sort our configurations so we can do binary-searches
277        qsort(configs, numTotalConfigs, sizeof(egl_config_t), cmp_configs);
278
279        refs++;
280        if (major != NULL)
281            *major = VERSION_MAJOR;
282        if (minor != NULL)
283            *minor = VERSION_MINOR;
284        return EGL_TRUE;
285    }
286    return setError(EGL_NOT_INITIALIZED, EGL_FALSE);
287}
288
289EGLBoolean egl_display_t::terminate() {
290
291    Mutex::Autolock _l(lock);
292
293    if (refs == 0) {
294        return setError(EGL_NOT_INITIALIZED, EGL_FALSE);
295    }
296
297    // this is specific to Android, display termination is ref-counted.
298    if (refs > 1) {
299        refs--;
300        return EGL_TRUE;
301    }
302
303    EGLBoolean res = EGL_FALSE;
304    for (int i = 0; i < IMPL_NUM_IMPLEMENTATIONS; i++) {
305        egl_connection_t* const cnx = &gEGLImpl[i];
306        if (cnx->dso && disp[i].state == egl_display_t::INITIALIZED) {
307            if (cnx->egl.eglTerminate(disp[i].dpy) == EGL_FALSE) {
308                LOGW("%d: eglTerminate(%p) failed (%s)", i, disp[i].dpy,
309                        egl_tls_t::egl_strerror(cnx->egl.eglGetError()));
310            }
311            // REVISIT: it's unclear what to do if eglTerminate() fails
312            free(disp[i].config);
313
314            disp[i].numConfigs = 0;
315            disp[i].config = 0;
316            disp[i].state = egl_display_t::TERMINATED;
317
318            res = EGL_TRUE;
319        }
320    }
321
322    // Mark all objects remaining in the list as terminated, unless
323    // there are no reference to them, it which case, we're free to
324    // delete them.
325    size_t count = objects.size();
326    LOGW_IF(count, "eglTerminate() called w/ %d objects remaining", count);
327    for (size_t i=0 ; i<count ; i++) {
328        egl_object_t* o = objects.itemAt(i);
329        o->destroy();
330    }
331
332    // this marks all object handles are "terminated"
333    objects.clear();
334
335    refs--;
336    numTotalConfigs = 0;
337    delete[] configs;
338    return res;
339}
340
341
342// ----------------------------------------------------------------------------
343}; // namespace android
344// ----------------------------------------------------------------------------
345