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