blob: 558ca77ff994b51061c5605b56d0f39f40ff6f43 [file] [log] [blame]
Mathias Agopian518ec112011-05-13 16:21:08 -07001/*
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
Jamie Gennisaca51c02011-11-03 17:42:43 -070017#include "egl_cache.h"
Mathias Agopian518ec112011-05-13 16:21:08 -070018#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;
Jamie Gennis76601082011-11-06 14:14:33 -080047 egl_cache_t::get()->terminate();
Mathias Agopian518ec112011-05-13 16:21:08 -070048}
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
Mathias Agopian5b287a62011-05-16 18:58:55 -070060void egl_display_t::removeObject(egl_object_t* object) {
61 Mutex::Autolock _l(lock);
62 objects.remove(object);
63}
64
Mathias Agopian518ec112011-05-13 16:21:08 -070065bool 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
Mathias Agopian518ec112011-05-13 16:21:08 -070074EGLDisplay 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
Jamie Gennisaca51c02011-11-03 17:42:43 -0700175 egl_cache_t::get()->initialize(this);
176
Mathias Agopian518ec112011-05-13 16:21:08 -0700177 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
Mathias Agopian5b287a62011-05-16 18:58:55 -0700258 // 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();
Mathias Agopian518ec112011-05-13 16:21:08 -0700270
271 refs--;
272 numTotalConfigs = 0;
273 delete[] configs;
274 return res;
275}
276
277
278// ----------------------------------------------------------------------------
279}; // namespace android
280// ----------------------------------------------------------------------------